Skip to content

Latest commit

 

History

History
199 lines (100 loc) · 10.6 KB

cobalstrike 免杀:三板斧再锤卡巴.md

File metadata and controls

199 lines (100 loc) · 10.6 KB

本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com

cobalstrike 免杀:三板斧再锤卡巴

1

概述

这次我们一起来探究如何规避卡巴的内存扫描,使得 cobalstrike 的 beacon 能够存活,主要原理就是:在 beacon 发送完心跳包 sleep,对自身的内存属性进行修改去除可执行属性和相关加密,其实现的方式有以下三种:

1、VEH Hook

2、SMC

3、InlineHook

下面会详细讲述各种方法。同时感谢 BGWill 师傅的文章,让我拓宽了见识。

相关代码已上传到项目中:

https://github.com/mai1zhi2/CobaltstrikeSource/

2

前置操作

在项目使用了自定义资源,并把 beacon 放在项目的资源中,然后通过解析自身的 pe 结构找到自身的资源,从而进行加载,beacon 放在资源可以自己异或加密,放在 bmp 图片后也是可以的:

3

VEHHook

VEHHook 是基于 windows 异常的一种 Hook,所以这里要介绍下 windows 异常处理机制。在 windows 中,当程序执行过程中发生异常时,系统内核的异常处理过程(nt!KiDispatchException)便开始工作。当在没有内核调试器存在且异常程序没有调试的情况下,windows 系统就会把异常处理过程转交给用户层的异常处理过程(ntdll!RtlDispatchException),用户层会查找异常程序中是否安装了 VEH、SHE、TopLevelExceptionHandler 等异常处理过程,如果已安装则交给其处理。

所以,我们需要先在 beacon 端安装相应的异常处理过程,然后在发送心跳包时硬编码写下 int3 断点指令,当程序执行到 int3 就会触发异常,就会在 windows 用户态触发相应的处理过程,VEH->SHE->TopLevelExceptionHandler。在这里我们使用 int3+VEH Hook,因为 VEH 是全局的、基于进程、优先级高。

先找到发送心跳包处:

然后在对应 pe 文件中找到相应的位置,硬编码上 int3 即 CC:

然后安装 VectoredHandler 过程,当程序执行到断定时产生异常,该异常会被 VectoredHandler 所捕获:

VectoredHandler() 如下,在函数中我们需要判断发生异常的地址是否与预期一致,里面的 context 结构体有详细的栈、寄存器信息:

Win10x64 执行效果:

Win7x86 执行效果:

执行任务时内存属性:

内存中的断点位置:

Sleep 时的内存属性:

4

SMC

SMC(Self-ModifyingCode),即能修改自身代码,对自己的代码进行打内存补丁。在 beacon 中,我们需要对心跳包的 sleep() 进行打补丁,将其修改我们自定义的 MySleep()。

这里需要注意的操作有,

1)因为 CS 的 beacon 是反射注入的,其反射注入的函数会对其进行重定位,所以我们需要对其 pe 的重定位数据进行修改,否则,在打内存补丁后,又被反射注入函数进行重定位,MySleep 的函数地址就会出错。这也是不能使用 IineHookCall IAT 的原因。

经过 pe 下数两行半等一系列数手指操作,找到需要修改的重定位数据:

2)自定义的 MySleep() 函数是 stdcall 的,不然栈会不平衡:

在 Mysleep() 中,需要找到反射注入 dll 所申请的内存区域,所以要从栈上找到返回地址,再去进行相应的判断,应该也能使用 egghunter 在内存中捞出所在区域。

3)修改资源中心跳包的 sleep() 函数地址:

Win10x64 执行效果:

Win7x86 执行效果:

Sleep 时的内存属性:

5

InlineHook

Inline Hook 是直接修改指令的 Hook,使得程序转移了所执行的流程,转移的方式也各异,主要有 jmpxxxxxxxx、pushxxxxxxxx/retn、moveax,xxxxxxxx/jmp eax、callHookAddr(输入表地址)、HotPatchHook。使用 InlineHook 要注意几个问题:

1、是当 Hook 操作时的线程安全问题,可以先暂停所有线程,再进行 Hook 操作,最后恢复线程去避免,而 IATHook 相当于原子操作,不存在这问题。因为我们这里是先 Hooksleep(),再进行反射注入,所以也不存在这问题。

2、Detour 函数重入,造成无限递归

3、Detour 函数的线程安全问题,避免使用全局变量,若使用则要上锁。

这里我们稍改了下教主的框架,没有使用微软的 InlineHook 框架。

这里先定义代替 Sleep() 函数的自定义函数,也即是 Detour():

里面的 OriginalSleep 函数是一条跳转回去执行系统的 Sleep() 通道, 里面需要恢复原来的指令,及绕过自己安装的 Hook:

获取到需要 Hook 函数的地址并记录,通过 LoadLibrary()、GetProcAddress() 获得系统 Sleep() 函数的地址,这里有个地方需要注意,或许因为编译版本不同,后面可能是 FF25Jmp 或 E9 call 或者其他,这里 debug 编译的是 FF25Jmp,我们需要获取到 Jmp 后面地址所指向的值,该值才是真正系统 Sleep() 函数位置:

在系统 Sleep() 地址上,写入自己的跳转代码,一个 E9Jmp 跳到先前自定义好的 Sleep():

可以看到系统的 Sleep() 函数已经被 Hook 了:

一个 Jmp 跳转到我们自定义的 MySleep() 中:

其中有个 E84E ED FF FF 这个 Call 是跳转回 OriginalSleep 函数,即跳转回去执行系统的 Sleep() 通道:

OriginalSleep 函数中一个 Jmp,绕过了 Hook,执行回系统的 Sleep() 函数:

至此 InlineHook 完成。

Win10x64 执行效果:

6

小结

这次我们通过相关 Hook 的方式,达到修改内存中 Beacon 的属性和数据等目的,但操作起来还是有点繁琐。谢谢大家观看,下次我们再继续深究。

参考:

https://xz.aliyun.com/t/9399#toc-1

加密与解密

7

关注

本公众号不定期更新安全类文章和视频 欢迎前来关注