freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Brute Ratel C4红队框架和EDR的猫鼠游戏
2022-08-09 01:30:51
所属地 浙江省

1.前言

Brute Ratel C4是类似于Cobalt Strike的商业红队框架,每年的License收费为$2500,首个版本Brute Ratel C4 v0.2 (Prometheus)于2021年2月9日发布,截至发稿最新发布版本v1.1(Stoffel's Escape)与2022年7月20日发布,相比与Cobalt Strike的知名度BRc4显然要低调的多,但是BRc4使用的技术和功能却丝毫不亚于CS,本次分析的样本使用的最终payload就是BRc4框架。

2.样本运行流程图

image

3.样本IOCs

名称: Roshan_CV.iso
大小: 4839424 字节 (4726 KiB)
MD5: a7df3462a6dce565064cfe408557c4df
SHA1: 6b91bfc761fe958c8ac04dd403db284ccc3a530e
SHA256: 1fc7b0e1054d54ce8f1de0cc95976081c7a85c7926c03172a3ddaa672690042c

名称: OneDrive.Update
大小: 277064 字节 (270 KiB)
MD5: d6eae771c6cb12e17028fa35e4fba295
SHA1: 70767d3f7ff7736063ee76c0d9c0e90ce895332b
SHA256: b5d1d3c1aec2f2ef06e7d0b7996bc45df4744934bd66266a6ebb02d70e35236e

名称: OneDriveUpdater.exe
大小: 4200864 字节 (4102 KiB)
MD5: 792e95b64b9cf45ac8bc10d4d0f077c2
SHA1: e50af7ee7e0a323d8aa60b6d9b3d39ab33b004f5
SHA256: 60e64dd2c6d2ac6fe9b498fadac81bc34a725de5d893e7df8b2728d8dc5b192d

名称: version.dll
大小: 259584 字节 (253 KiB)
MD5: 76fa734236daa023444dec26863401dc
SHA1: a68a1b7ca1d1ddd005fd10382bf6cd0b86e74e86
SHA256: ea2876e9175410b6f6719f80ee44b9553960758c7d0f7bed73c0fe9a78d8e669

名称: vresion.dll
大小: 31496 字节 (30 KiB)
MD5: 17c1e1099b65051bb6dec71fea37315b
SHA1: 8ed26469afbd53da7749ef9c6ab8c7f010e9bb1e
SHA256: e549d528fee40208df2dd911c2d96b29d02df7bef9b30c93285f4a2f3e1ad5b0

名称: Roshan-Bandara_CV_Dialog
大小: 3149 字节 (3.07 KiB)
MD5: 82eb32d941b6dd63957a37453c9b0333
SHA1: f27a374044c73a6a5b2d926bb9468daf570b8bfc
SHA256: 4466017fd40c4b5fa9923928b7be3acf03825b4dd8c5fcf088992aee398b8c2d

4.恶意代码分析

恶意样本是个iso文件,双击挂载iso,一共有5个文件,除了Roshan-Bandara_CV_Dialog这个快捷方式之外其他的文件都是隐藏文件(我开启了显示隐藏文件所以这里全部显示了)
image
我们查看Roshan-Bandara_CV_Dialog快捷方式指向的目标%windir%/system32/cmd.exe /c start OneDriveUpdater.exe,主要就是调用cmd命令执行了隐藏文件OneDriveUpdater.exe,cmd.exe /c命令指定执行完后会自动关闭控制台窗口
image
我们接着看这个快捷方式的图标文件,发现其图标文件指向%ProgramFiles%\Microsoft Office\root\Office16\WINWORD.EXE,由于本机没有装Office 2016所以此快捷方式的图标就无法显示,由此可见此次攻击样本十分有针对性
image
其中的vresion.dll和OneDriveUpdater.exe为白文件都有Microsoft的有效数字签名
image
其中的version.dll链接器版本14.29是使用1929 (Visual Studio 2019 Version 16.10 + 16.11)编译的64位DLL,可以看到编译时间戳为2022-5-17 16:35:50
image
version.dll和vresion.dll的导出函数完全相同
image
OneDrive.Update是一个被加密的二进制文件,猜测可能是shellcode或者pe文件
image
使用ida64打开OneDriveUpdater.exe分析,我们可以看到OneDriveUpdater.exe一共调用了version.dll中的3个导出函数
image
接下来我们使用ida64分析version.dll,查看version.dll的导出函数时发现并没有相关的实现,而是使用了导出函数转发技术将函数转发到白文件vresion.dll的实现
image

4.1 stage0:version.dll代码分析

接下来我们分析version.dll的DllMain函数,只调用了一个sub_180002090函数
image
sub_180002090函数使用了WTSEnumerateProcessesA函数枚举进程
image
循环查找RuntimeBroker.exe进程
image
读取加密文件OneDrive.Update到内存
image
控制台窗口打印字符串"Please wait..."
image
先调用了NtDelayExecution函数休眠了几秒,接着调用NtOpenProcess函数以PROCESS_ALLACCESS权限打开RuntimeBroker.exe进程
image
此样本的NtOpenProcess函数实现,这些汇编代码特征让我想到了SysWhispers3项目
image
这是我使用SysWhispers3项目生成的NtOpenProcesss的syscall调用,发现除了SysWhispers3使用函数Hash方式之外汇编代码特征完全一致,可以判断此样本使用了SysWhispers3项目
image
接下来我们详细分析下首先SW3_GetSyscallEGG_180001D20函数参数为ntop
image
主要逻辑是通过gs:[60]获取PEB,然后通过偏移找到PEB->Ldr->InMemoryOrderModuleList链表,并通过访问LDR_DATA_TABLE_ENTRY->FullDllName字段使用_stricmp函数判断找到ntdll.dll
image
接下来通过解析ntdll.dll的PE结构获取导出函数
image
第一个导出函数名称
image
memcmp函数对比直到找到导出函数NtOpenProcess
image
最终获取到导出函数地址
image
接下来通过搜索函数NtOpenProcess的OPCODE特征找到syscall(0F05)的地址(EGG)
image
接下来分析SW3_GetSyscallNumber_180002000函数,主要逻辑还是通过OPCODE特征搜索找到syscall id,关于syscall id对应的函数在不同windows版本下不同可以在j00ru的博客查询
image
此时RAX为NtOpenProcess函数的syscall id:26,r15为syscall的地址
image
通过syscall调用NtOpenProcess函数
image
接下来使用硬编码的xor密钥jikoewarfkmzsdlhfnuiwaejrpaw解密OneDrive.Update,解密大小为0x493E0
image
调用了NtCreateSection函数创建0x493E0大小的PAGE_EXECUTE_READWRITE内存权限,SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE访问属性的section
image
接着调用NtMapViewOfSection函数将section映射到本进程虚拟内存
image
并调用NtMapViewOfSection函数将section映射到RuntimeBroker.exe进程虚拟内存
image
使用memmove函数将解密后的shellcode复制到本进程section共享内存空间,此时section内存会同步映射到远程进程RuntimeBroker.exe进程虚拟内存
image
然后调用NtCreateThreadEx函数在RuntimeBroker.exe进程中创建远程线程执行注入的shellcode
image
我们使用processhack工具查看RuntimeBroker.exe进程内存可以看到shellcode已经注入成功
image

4.2 stage1:OneDrive.Update代码分析

为了方便调试我将stage0解密后的shellcode从内存中dump下来并使用自写的shellcode loader加载调试分析,shellcode开头有巨量的movpush执行的组合,通过压入栈中的数据可以判断大致是在初始化数据和函数调用要用到的参数等等
image
在偏移0x43750处才开始主要逻辑
image
可以看到刚刚压入栈中的众多数据包含了一个PE文件并且此PE文件的Dos头的MZSignature(0x5A4D)被抹除防止EDR进行内存扫描查杀,通过访问0x3C位置AddressOfNewExeHeader开始解析此PE文件
image
最终获取导出函数的RVA:0x92E0
image
接下来的逻辑还是熟悉的通过PEB-Ldr->InMemoryOrderModuleList获取ntdll.dll的基址
image
然后调用FindHashFunAddress_5137AE函数通过函数Hash获取对应函数的地址
image
通过解析ntdll.dll的PE结构获取导出函数名称表
image
并对导出函数名进行ror13 Hash然后对比目标函数Hash直到找到需要的函数
image
获取到需要的导出函数地址后会调用CheckFuninlineHook_51375B函数进行检查
image
首先检查函数头是否被下了int3软件断点(0xCC),然后通过检测OPCODE编码E9(jmp)判断函数是否被EDR给inlineHook,如果函数正常则通过偏移获取函数的syscall id
image
接着将参数压栈,通过syscall调用ZwAllocateVirtualMemory申请PAGE_READWRITE权限的内存
image
接着又申请了一块内存PAGE_READWRITE权限的内存
image
申请完内存后调用了CopyPeToAllocAddress_513815函数
image
此函数将栈中的PE文件(0x3240)大小的内容以每次QWORD大小复制到申请的虚拟内存中
image
PE文件复制完成
image
接着调用 MemSetPeMemoryFeatures_513805函数将内存中PE文件Dos头除了AddressOfNewExeHeader字段以外的内存置0,防止EDR扫描内存查杀
image
又调用了MemSetPeMemoryFeatures_513805函数将内存中PE文件DosStub部分的内存置0
image
接着调用CopyBase64ToAllocAddress_513820函数
image
将0x148字节大小的Base64编码数据复制到申请的第二块虚拟内存中
image
复制完内存后还是通过调用FindHashFunAddress_5137AE函数通过函数Hash获取ZwProtectVirtualMemory函数地址
image
调用ZwProtectVirtualMemory将存放PE文件那块内存属性改为PAGE_EXECUTE_READ属性
image
获取了ZwCreateThreadEx的syscall id
image
调用ZwCreateThreadEx执行的函数为函数开头获取的导出函数
image
调用ZwWaitForSingleObject函数等待线程执行完毕
image

4.3 stage2:ReflectiveDLLInjection代码分析

stage1创建的线程执行的函数入口,搜索内存找到Nt头的Signature(PE)地址,通过kernel32.dll的hash获取基址
image
访问PEB->Ldr->InMemoryOrderModuleList链表并对FullDllName进行ror13 Hash
image
对比Hash正确
image
获得kernel32.dll基址
image
函数GetNtdllAddress_66b2c0通过PEB加偏移获取ntdll.dll的基址
image
接下来调用GetFunAddressByHash_668050函数通过Hash获取6个对应函数的地址
image
通过解析kernel32.dll的PE结构导出表,对导出函数进行Hash对比找到对应的函数
image
成功获取LoadLibraryA函数地址
image
获取完需要的函数地址之后,对于ntdll的导出函数进行inlineHook检测并动态获取对应的syscall id
image
检测函数是否被下int3软件断点,并检测函数头前7个字节OPCODE是否和函数固定特征相同,最后通过固定偏移获取syscall id
image
通过BRc4官网的功能介绍可知检测EDR的HOOK是BRc4的主要功能之一
image
此时rax为动态获取的syscall id
image
通过此函数获取了4个ntdll的导出函数syscall id
image
syscall(间接系统调用)也是BRc4官网介绍的主要功能特征
image
调用NtSetInformationProcess函数并设置参数PROCESS_INFOMATION_CLASS为0x28
image
通过syscall id调用NtSetInformationProcess函数
image
调用NtAllocateVirtualMemory函数申请了PAGE_READWRITE权限的内存
image
syacall id调用NtAllocateVirtualMemory函数
image
接下来将PE头0x400字节复制到了新申请的内存,通过前面获取的函数地址和此复制操作有分析过类似样本的应该可以大致推断这是ReflectiveDLLInjection(反射式注入),主要逻辑就是模拟系统的PE Loader将PE文件复制到可执行内存中并修复IAT处理重定位数据然后直接调用内存中的函数执行,虽然这是10年前发布的技术但metasploit和cobalt strike等等框架还是普遍有使用ReflectiveDLLInjection技术,此方式可以避免文件落地以减少EDR查杀
image
接着将全部section逐个复制到新内存
image
复制下一个section
image
复制完全部secsion后开始获取IAT函数地址填充修复IAT
image
循环直到修复完IAT
image
修复重定位数据
image
调用NtFlushInstructionCache函数刷新缓存
image
调用NtProtectVirtualMemory修改各个section的内存权限
image
所有section被更改的内存权限
image
我们使用processhack工具查看内存中各个区段的权限
image
之后将PE头0x200字节内存置0,防止EDR扫描内存特征查杀
image
最后调用dllmain
image

4.4 stage3:DllPayload代码分析

我们将内存中的PE文件dump出来,可以看到此PE文件为MinGW-w64编译的x64 DLL
image
编译时间戳为2022-3-26 4:51:36,一共有11个sections
image
有一个无名导出函数为ReflectiveDLLInjection
image
接下来我们分析dllmain的两个函数sub_7A1500和sub_7A1FB0
image
sub_7A1500函数通过多个时间戳函数和进程线程ID异或获得12位的唯一ID
image
sub_7A1FB0函数主要检测确保内存中PE文件的MZSignature(MZ)NtHeaderSignature(PE00)被抹除
image
接下来分析主要的核心函数,通过Hash获取VirtualFree函数释放了不需要的两处内存
image
SendRecvDataC2Server_61F89060函数就是主要的加密解密和收发数据到C2服务器
image
GetAllNeedFunAddressbyHash_61F83A30获取了全部需要用到的函数地址,首先获取了kernel32.dll中需要的函数(由于篇幅限制只截取了部分获取dll导出函数的截图)
image
获取ntdll.dll中需要用到的函数
image
除了获取kelnel32.dll和kernelbase.dll和ntdll.dll基址使用了通过PEB加Hash方式,获取其它DLL都使用RC4密钥bYXJm/3#M?:XyMBF解密dll字符串并使用LoadLibraryA加载
image
获取通过syscall方式调用的ntdll.dll的导出函数syscall id
image
最后获取了wininet.dll中的导出函数
image
接下来DecryptBase64ReqHeader_61F88DC0函数主要解密了base64参数
image
initDecBox9_61F8B100函数初始化了Brute Ratel C4自定义加密算法需要用的9个box[256],初始化方法将box中每位元素减1
image
此为其中一个box
image
base64解码
image
使用了CryptStringToBinaryA函数解码base64,可以看到解码后的数据还是乱码
image
之后使用rc4算法和硬编码的密钥bYXJm/3#M?:XyMBF解密后的数据可以看到有C2的ip地址User-Agent以及一些配置信息
image
对于解密的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
image
base64解码配置数据头的eyJjb29raWUiOiI=
image
base64解码In0=
image
接下来GetSysInfo_61F99FC0函数主要是调用函数获取了用户名进程PID系统版本和位数等等信息
image
获取的当前进程的绝对路径
image
并使用base64编码
image
获取完数据初始化winsocket版本为2.2
image
函数EncryptDataAndConnectC2_61F8C760首先将将获取到的的系统信息格式化
image
格式化后的数据
image
这里使用了Brute Ratel C4自定义的加密算法密钥2Q73HI7Q0OD5BRN7加密了数据
image
关于Brute Ratel C4自定义的加密算法官网有进行说明,此加密用于加密和BRc4服务器之间的网络数据,这层加密是在ssl层之下
image
对于Brute Ratel C4的自定义加密算法其实就是一个比较复杂的xor加密,这里使用我逆向还原的c++代码,关于完整的加密解密算法源码感兴趣的可以去我的github,首先InitXorKeyBox函数根据key2Q73HI7Q0OD5BRN7生成160字节xorkey,函数首先获取key的后4字节传入replaceFourByteKey函数
image
replaceFourByteKey函数首先将4字节的key进行ror 8,然后以第1个字节数据当作g_Box1的数组下标取出值异或g_Box2[g_replaceIndex],g_replaceIndex默认值为1每次调用replaceFourByteKey函数值+1,这是第1个字节的处理方式
image
2到4字节处理方式是直接将数据当作g_Box1的数组下标取出值直接进行替换
image
replaceFourByteKey函数处理完的4字节数据会和key的前4字节异或生成第二组xorkey的前4字节
image
第二组xorkey后面每4字节都是通过前4字节的key异或前一组xorkey的后4字节,这里33 ^ 48生成的就是第二组xorkey的第5个字节,剩下的以此类推
image
通过以上流程一共176字节11组xorkey生成完毕
image
接下来这是EncryptData函数的主要逻辑也就是全部的加密过程,每次加密16字节的明文数据
image
首先调用MyXor函数使用第一组xorkey逐字节和明文数据进行异或
image
接着replaceBoxData函数将数据作为g_Box1的数组下标进行替换
image
接着调用ByteOutOfOrder函数将数据乱序
image
boxXorData函数一共是处理了16字节,我这里就贴了前4个字节的图,因为加密方式都相同主要就是数据作为g_box3和g_box4数组下标取出的值进行异或
image
再次调用MyXor函数对数据进行异或,本次使用的就是第二组xorkey,这里循环9次前面的3个函数流程相同,MyXor函数一共使用9组xorkey进行异或加密
image
最后一层加密除了没有调用boxXorData函数其他的调用顺序和9次循环加密里的逻辑相同,至此16字节的明文数据加密完毕,开始加密下16字节的明文数据
image
通过以上加密算法加密后的数据进行base64编码
image
使用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
image
InternetConnectW函数设置C2的ip地址174.129.157.251和端口443
image
HttpOpenRequestW函数涉资请求类型为POST并且请求路径为/content.html
image
InternetSetOptionW设置Internet选项为INTERNET_OPTION_SECURITY_FLAGS
image
HttpAddRequestHeadersW函数参数HTTP_ADDREQ_FLAG_ADD
image
向C2发送POST请求
image
COFFLoader(BOFs)功能部分代码
image
C-Sharp内存加载部分代码
image
由此分析对比官网介绍的C-Sharp、BOFs内存加载功能
image
ETW patch功能使用的方案是直接将EtwEventWrite函数头改写C3(ret)让函数直接返回,由于没有动态调试我通过自己写的ror13Hash小工具确认函数Hash
image
image
AMSI patch的方案是将AmsiScanBuffer函数头改写为B8 57 00 07 80 C3(mov eax,0x80070057;ret)
image
image
我们反汇编amsi.dll可知如果AmsiScanBuffer函数判断传入参数错误的话会跳过扫描分支过程直接将返回值0x80070057存放eax并返回,所以这里的patch方案也是直接将0x80070057存放eax并直接ret返回
image

5.总结

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

# 恶意软件 # 逆向工程 # 红队工具 # Brute Ratel C4 # BRc4
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录