Brute Ratel C4红队框架和EDR的猫鼠游戏(下)
2022-9-23 08:5:7 Author: 红队蓝军(查看原文) 阅读量:132 收藏

承接上文 Brute Ratel C4红队框架和EDR的猫鼠游戏(上)

yauv,公众号:红队蓝军Brute Ratel C4红队框架和EDR的猫鼠游戏(上)

4.3 stage2:ReflectiveDLLInjection代码分析

stage1创建的线程执行的函数入口,搜索内存找到Nt头的Signature(PE)地址,通过kernel32.dll的hash获取基址

访问PEB->Ldr->InMemoryOrderModuleList链表并对FullDllName进行ror13 Hash

对比Hash正确

获得kernel32.dll基址

函数GetNtdllAddress_66b2c0通过PEB加偏移获取ntdll.dll的基址

接下来调用GetFunAddressByHash_668050函数通过Hash获取6个对应函数的地址

通过解析kernel32.dll的PE结构导出表,对导出函数进行Hash对比找到对应的函数

成功获取LoadLibraryA函数地址

获取完需要的函数地址之后,对于ntdll的导出函数进行inlineHook检测并动态获取对应的syscall id

检测函数是否被下int3软件断点,并检测函数头前7个字节OPCODE是否和函数固定特征相同,最后通过固定偏移获取syscall id

通过BRc4官网的功能介绍可知检测EDR的HOOK是BRc4的主要功能之一

此时rax为动态获取的syscall id

通过此函数获取了4个ntdll的导出函数syscall id

syscall(间接系统调用)也是BRc4官网介绍的主要功能特征

调用NtSetInformationProcess函数并设置参数PROCESS_INFOMATION_CLASS为0x28

通过syscall id调用NtSetInformationProcess函数

调用NtAllocateVirtualMemory函数申请了PAGE_READWRITE权限的内存

syacall id调用NtAllocateVirtualMemory函数

接下来将PE头0x400字节复制到了新申请的内存,通过前面获取的函数地址和此复制操作有分析过类似样本的应该可以大致推断这是ReflectiveDLLInjection(反射式注入),主要逻辑就是模拟系统的PE Loader将PE文件复制到可执行内存中并修复IAT处理重定位数据然后直接调用内存中的函数执行,虽然这是10年前发布的技术但metasploit和cobalt strike等等框架还是普遍有使用ReflectiveDLLInjection技术,此方式可以避免文件落地以减少EDR查杀

接着将全部section逐个复制到新内存

复制下一个section

复制完全部secsion后开始获取IAT函数地址填充修复IAT

循环直到修复完IAT

修复重定位数据

调用NtFlushInstructionCache函数刷新缓存

调用NtProtectVirtualMemory修改各个section的内存权限

所有section被更改的内存权限

我们使用processhack工具查看内存中各个区段的权限

之后将PE头0x200字节内存置0,防止EDR扫描内存特征查杀

最后调用dllmain

4.4 stage3:DllPayload代码分析

我们将内存中的PE文件dump出来,可以看到此PE文件为MinGW-w64编译的x64 DLL

编译时间戳为2022-3-26 4:51:36,一共有11个sections

有一个无名导出函数为ReflectiveDLLInjection

接下来我们分析dllmain的两个函数sub_7A1500和sub_7A1FB0

sub_7A1500函数通过多个时间戳函数和进程线程ID异或获得12位的唯一ID

sub_7A1FB0函数主要检测确保内存中PE文件的MZSignature(MZ)NtHeaderSignature(PE00)被抹除

接下来分析主要的核心函数,通过Hash获取VirtualFree函数释放了不需要的两处内存

SendRecvDataC2Server_61F89060函数就是主要的加密解密和收发数据到C2服务器

GetAllNeedFunAddressbyHash_61F83A30获取了全部需要用到的函数地址,首先获取了kernel32.dll中需要的函数(由于篇幅限制只截取了部分获取dll导出函数的截图)
获取ntdll.dll中需要用到的函数

除了获取kelnel32.dll和kernelbase.dll和ntdll.dll基址使用了通过PEB加Hash方式,获取其它DLL都使用RC4密钥bYXJm/3#M?:XyMBF解密dll字符串并使用LoadLibraryA加载

获取通过syscall方式调用的ntdll.dll的导出函数syscall id

最后获取了wininet.dll中的导出函数

接下来DecryptBase64ReqHeader_61F88DC0函数主要解密了base64参数

initDecBox9_61F8B100函数初始化了Brute Ratel C4自定义加密算法需要用的9个box[256],初始化方法将box中每位元素减1

此为其中一个box

base64解码

使用了CryptStringToBinaryA函数解码base64,可以看到解码后的数据还是乱码

之后使用rc4算法和硬编码的密钥bYXJm/3#M?:XyMBF解密后的数据可以看到有C2的ip地址User-Agent以及一些配置信息

对于解密的User-AgentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36和Brute Ratel C4官网的Documentation的Listener Profile配置教程中User-Agent完全一致,可以判断此样本就是Brute Ratel C4生成的payload

base64解码配置数据头的eyJjb29raWUiOiI=

base64解码In0=

接下来GetSysInfo_61F99FC0函数主要是调用函数获取了用户名进程PID系统版本和位数等等信息

获取的当前进程的绝对路径

并使用base64编码

获取完数据初始化winsocket版本为2.2

函数EncryptDataAndConnectC2_61F8C760首先将将获取到的的系统信息格式化

格式化后的数据

这里使用了Brute Ratel C4自定义的加密算法密钥2Q73HI7Q0OD5BRN7加密了数据

关于Brute Ratel C4自定义的加密算法官网有进行说明,此加密用于加密和BRc4服务器之间的网络数据,这层加密是在ssl层之下

对于Brute Ratel C4的自定义加密算法其实就是一个比较复杂的xor加密,这里使用我逆向还原的c++代码,关于完整的加密解密算法源码感兴趣的可以去我的github,首先InitXorKeyBox函数根据key2Q73HI7Q0OD5BRN7生成160字节xorkey,函数首先获取key的后4字节传入replaceFourByteKey函数

replaceFourByteKey函数首先将4字节的key进行ror 8,然后以第1个字节数据当作g_Box1的数组下标取出值异或g_Box2[g_replaceIndex],g_replaceIndex默认值为1每次调用replaceFourByteKey函数值+1,这是第1个字节的处理方式

2到4字节处理方式是直接将数据当作g_Box1的数组下标取出值直接进行替换

replaceFourByteKey函数处理完的4字节数据会和key的前4字节异或生成第二组xorkey的前4字节

第二组xorkey后面每4字节都是通过前4字节的key异或前一组xorkey的后4字节,这里33 ^ 48生成的就是第二组xorkey的第5个字节,剩下的以此类推

通过以上流程一共176字节11组xorkey生成完毕

接下来这是EncryptData函数的主要逻辑也就是全部的加密过程,每次加密16字节的明文数据

首先调用MyXor函数使用第一组xorkey逐字节和明文数据进行异或

接着replaceBoxData函数将数据作为g_Box1的数组下标进行替换

接着调用ByteOutOfOrder函数将数据乱序

boxXorData函数一共是处理了16字节,我这里就贴了前4个字节的图,因为加密方式都相同主要就是数据作为g_box3和g_box4数组下标取出的值进行异或

再次调用MyXor函数对数据进行异或,本次使用的就是第二组xorkey,这里循环9次前面的3个函数流程相同,MyXor函数一共使用9组xorkey进行异或加密

最后一层加密除了没有调用boxXorData函数其他的调用顺序和9次循环加密里的逻辑相同,至此16字节的明文数据加密完毕,开始加密下16字节的明文数据

通过以上加密算法加密后的数据进行base64编码

使用InternetOpenW函数设置User-Agent为Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36

InternetConnectW函数设置C2的ip地址174.129.157.251和端口443

HttpOpenRequestW函数涉资请求类型为POST并且请求路径为/content.html

InternetSetOptionW设置Internet选项为INTERNET_OPTION_SECURITY_FLAGS

HttpAddRequestHeadersW函数参数HTTP_ADDREQ_FLAG_ADD

向C2发送POST请求
COFFLoader(BOFs)功能部分代码

C-Sharp内存加载部分代码

由此分析对比官网介绍的C-Sharp、BOFs内存加载功能

ETW patch功能使用的方案是直接将EtwEventWrite函数头改写C3(ret)让函数直接返回,由于没有动态调试我通过自己写的ror13Hash小工具确认函数Hash


AMSI patch的方案是将AmsiScanBuffer函数头改写为B8 57 00 07 80 C3(mov eax,0x80070057;ret)


我们反汇编amsi.dll可知如果AmsiScanBuffer函数判断传入参数错误的话会跳过扫描分支过程直接将返回值0x80070057存放eax并返回,所以这里的patch方案也是直接将0x80070057存放eax并直接ret返回

Brute Ratel C4是一款非常优秀的商业红队C2框架,使用了众多用于规避和检测EDR的技术,在最新版的BRc4 v1.1(Stoffel's Escape)的更新日志中作者宣布已经对核心程序进行了重写以隐藏内存的的几处痕迹,并且不再更新试用许可证,新申请试用许可证只会获得 v1.0.x 版本的最新更新。作者称此举是为了防止试用用户将最新的payloads上传到Virus Total,可见BRc4作者为了对抗EDR厂商获取最新的payloads分析以进行针对性查杀的努力,BRc4作者的总结很到位这是一场EDR和BRc4之间的猫捉老鼠游戏。

https://www.freebuf.com/articles/system/341336.html

wx

rundll32

Windows defender 

360

webshell

360 | 

webshell


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NDY2MTQ1OQ==&mid=2247503369&idx=1&sn=60007e5a3820443559bf3c8a44ed43b7&chksm=ce6774b5f910fda38b1714e7b391b2577a45db2c8791ae0bde5cb1459a34051fb79b4b064133#rd
如有侵权请联系:admin#unsafe.sh