blockdlls
Cobalt Strike 3.14版本以后添加了blockdlls功能,它将创建一个子进程并限定该子进程只能加载带有Microsoft签名的DLL。
这个功能可以阻止第三方安全软件向子进程注入DLL,也就无法对子进程进行hook,最终起到保护子进程的效果。
XPN在博客中分享了实现同样功能的c代码
#include <Windows.h>
int main()
{
STARTUPINFOEXA si;
PROCESS_INFORMATION pi;
SIZE_T size = 0;
BOOL ret;
// 请求一个 STARTUPINFOEXA 结构体
ZeroMemory(&si, sizeof(si));
si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
si.StartupInfo.dwFlags = EXTENDED_STARTUPINFO_PRESENT;
//获取要分配的 PROC_THREAD_ATTRIBUTE_LIST 大小
InitializeProcThreadAttributeList(NULL, 1, 0, &size);
//为 PROC_THREAD_ATTRIBUTE_LIST 分配内存
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
GetProcessHeap(),
0,
size
);
// 初始化我们的列表
InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
// 启用阻止未经Microsoft签名的DLL功能
DWORD64 policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;
// Assign our attribute
UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &policy, sizeof(policy), NULL, NULL);
// 创建进程
ret = CreateProcessA(
NULL,
(LPSTR)"C:\Windows\System32\cmd.exe",
NULL,
NULL,
true,
EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
reinterpret_cast<LPSTARTUPINFOA>(&si),
&pi
);
}
通过STARTUPINFOEX结构体指定了要创建子进程的安全策略(开启PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON),这个安全策略起到了阻止加载非Microsoft签名dll的作用。
生成子进程后,使用ProcessHacker能够看到开启blockdlls功能的提示,如下图:
开启blockdlls功能后,尝试对这个进程进行dll注入,注入的代码可参考三好学生
注入时报错,提示如图:
接下来,需要了解此功能相关细节。在微软官方文档中,找到了相关API GetProcessMitigationPolicy(),可读取进程的安全策略。
而签名策略对应的结构体为PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY,资料显示该API支持的最低系统为Win8,这里猜测API GetProcessMitigationPolicy()同blockdlls支持的操作系统版本应该相同。
经过测试,发现Cobalt Strike中blockdlls支持的系统最低为Win8。
分析blockdlls在CS中的实现
如果我们搜索CS beacon二进制文件,我们会看到对UpdateProctThreadAttribute的引用:
0x20007的属性参数实际上定义为PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,并且0x10000000000的值解析为PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON。所以Cobalt Strike在这里所做的是使用CreateProcess API调用以及包含一个缓解策略的结构体STARTUPINFOEX,而该策略正是用于阻止非微软签名DLL的加载。
任意代码保护
ACG是Windows系统的另一个安全策略,用于阻止外部代码分配和/或修改内存,这里不多赘述。
要了解此缓解策略的实际效果,我们创建一个小程序并尝试使用 SetMitigationPolicy 添加开启 ACG :
#include <iostream>
#include <Windows.h>
#include <processthreadsapi.h>
int main()
{
STARTUPINFOEX si;
DWORD oldProtection;
PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy;
ZeroMemory(&policy, sizeof(policy));
policy.ProhibitDynamicCode = 1;
void* mem = VirtualAlloc(0, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (mem == NULL) {
printf("[!] Error allocating RWX memory
");
}
else {
printf("[*] RWX memory allocated: %p
", mem);
}
printf("[*] Now running SetProcessMitigationPolicy to apply PROCESS_MITIGATION_DYNAMIC_CODE_POLICY
");
// Set our mitigation policy
if (SetProcessMitigationPolicy(ProcessDynamicCodePolicy, &policy, sizeof(policy)) == false) {
printf("[!] SetProcessMitigationPolicy failed
");
return 0;
}
// Attempt to allocate RWX protected memory (this will fail)
mem = VirtualAlloc(0, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (mem == NULL) {
printf("[!] Error allocating RWX memory
");
}
else {
printf("[*] RWX memory allocated: %p
", mem);
}
void* ntAllocateVirtualMemory = GetProcAddress(LoadLibraryA("ntdll.dll"), "NtAllocateVirtualMemory");
// Let's also try a VirtualProtect to see if we can update an existing page to RWX
if (!VirtualProtect(ntAllocateVirtualMemory, 4096, PAGE_EXECUTE_READWRITE, &oldProtection)) {
printf("[!] Error updating NtAllocateVirtualMemory [%p] memory to RWX
", ntAllocateVirtualMemory);
}
else {
printf("[*] NtAllocateVirtualMemory [%p] memory updated to RWX
", ntAllocateVirtualMemory);
}
}
view raw
编译并执行这段代码,我们将看到如下内容:
我们可以看到在 SetProcessMitigationPolicy 失败后尝试分配 RWX 的内存页,以及使用诸如 VirtualProtect 之类的调用来分配或修改内存保护,结果都是失败的。
那为什么要提这个呢? 因为我们确实看到了由微软签名的 EDR 注入DLL的例子,@Sektor7Net 展示了 Crowdstrike Falcon 可以不受 PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON 的影响
但许多EDR产品常见的操作是将他们的DLL注入到其想监测的进程中,围绕特定的API函数实现用户态hook技术(参考文章)。由于hook技术通常需要修改现有的可执行内存页以添加hook,因此EDR通常需要调用VirtualProtect来更新内存保护。如果我们在恶意软件设计上启用ProcessDynamicCodePolicy可能有助于保护其免受EDR hook监测的影响,就可能会强制阻止一个带微软签名的DLL加载。
总结
现在,我们要将这些策略进行整合,在生成恶意进程时,可以用PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON以及SetMitigationPolicyAPI调用进行保护。当然,还有其他方法可以对进程进行保护,例如通过简单的CreateProcessA生成任意进程。
这里,我仅根据以上展开的思路编写了新款免杀马(开源是不可能开源的,只提供思路大家自行创作),通杀国内外一流杀软,命名“冢虎”,在座的各位师傅有谁赞同,有谁反对?
参考:
https://blog.cobaltstrike.com/2019/05/02/cobalt-strike-3-14-post-ex-omakase-shimasu/
https://www.ired.team/offensive-security/defense-evasion/acg-arbitrary-code-guard-processdynamiccodepolicy#enabling-acg
https://blog.xpnsec.com/protecting-your-malware/
https://www.4hou.com/posts/0Xov