安全矩阵

 找回密码
 立即注册
搜索
查看: 846|回复: 0

自动化提取恶意文档中的shellcode

[复制链接]

249

主题

299

帖子

1391

积分

金牌会员

Rank: 6Rank: 6

积分
1391
发表于 2023-2-2 09:19:26 | 显示全部楼层 |阅读模式
原文链接:自动化提取恶意文档中的shellcode



本文为看雪论坛优秀文章
看雪论坛作者ID:g0mx


shellcode提取器的应用对象是Maldoc,通过将市面上存在的相关分析工具进行组合,形成工具链,达到自动化定位及提取shellcode的目的。
语言及环境
    语言:python + javascript
    环境:REMnux docker + win7 (注:不使用RTF中的动态方法,可以摒弃win7,但面对一下经混淆的RTF文件可能无法正确提取shellcode)
    The docker image(g0mx/remnux-shellcode_extractor) created by myself for extracting shellcode from maldoc based on REMnux
    项目地址:https://github.com/g0mxxm/shellcode_extractor_for_maldoc
实现细节
实现并不复杂,本人认为该工具的实现思路是它的闪光点。实现思路,即将分析人员手动定位并提取shellcode的步骤自动化。
整体流程主要由解包、定位、提取这三个环节组成,后续的优化并不会改变整体流程。
    解包:针对RTF文件中OLE对象的定位和提取,本工具采用了动态和静态两种方式来解决此问题,二者也各有利弊。静态方式主要轮子取自Didier Stevens工具集,动态方式是本人基于frida hook框架编写了几个脚本来实现的,后文会进行详细阐述;针对OOXML文件的解包,主要轮子取自Didier Stevens工具集;针对OLE对象的解包,主要轮子取自Didier Stevens工具集。此外,该阶段会对文档类型及是否加密进行判断,主要轮子取自于oletools工具集,若加密则进行解密,随后进入下一环节;若未加密,则直接进入下一阶段。
    定位:主要轮子取自Didier Stevens工具集,其主要思想为遍历及暴力破解,首先对OLE对象进行解包,随后对其每个子stream进行暴力破解,特征匹配,以达到定位shellcode的目的。
    提取:主要轮子取自于Didier Stevens工具集,很简单的一步,定位后尝试对目标位置进行解码,随后dump即可得到最终的shellcode
解包
判断文件类型
通过oleid检查maldoc的基本信息,并根据其中Container format字段的键值判断该文件的具体类型,根据类型进入不同的分支,但最终都会走入OLE对象处理分支。
检查该文档是否被加密
通过oleid检查maldoc的基本信息,根据其中的Encrypted字段的键值判断该文件是否被加密。
若该文件被加密,可以通过msoffcrypto-crack对密码进行爆破,并保存完成解密的文件。
文件类型
RTF文件
本人对RTF文件的处理主要分为静态和动态两种形式,其中静态的优点在于可以不依赖于Windows环境,直接基于REMnux来完成OLE对象及其中shellcode的提取操作,但面对一些经过特殊混淆的RTF文件时,可能不能有效识别其中的OLE对象,因而本人基于frida实现了一个动态定位并获取OLE对象的工具,该工具的灵感来源于Denis O'Brien大佬的一篇文章(Reference中最后一项)
静态方法
静态方法主要利用Didier Stevensrtfdump工具中最新更新的“-F”选项,其在blog中说到,该选项是由“-H”和“-S”演变过来的,简单根据源码说一下本人对这两个选项功能的理解。
-H”和“-S”主要由HexDecode这个函数来实现,其功能是对字节流进行处理,并将其转换为十六进制的形式,其中包含判读奇偶和补零操作(-S)。虽然一个正常的hex流其肯定应该是偶数位的,这样才有正确解析的可能,但由于一些RTF解析器会对hex流为奇数位(有些maldoc构造者为了逃避检测会在hex流最后的位置额外添加一个十六进制字符)的问题进行处理,以完成解析,因此该函数中的判断奇偶和补零操作,应该就是为了正确解析进行了这种混淆操作的字节流;同样其也可以对抗在hex流中添加了大量空白字符这种混淆手法。本人对RTF的混淆方式了解还不是很全面,难免会有纰漏,欢迎指正和补充。
具体源码如下:
通过-F”选项找到所有OLE对象后,将所有OLE对象的标识保存下来,为后续提取做准备。
将所有找到的OLE对象,根据标识定位并保存下来,传给OLE对象处理模块,进行后续处理。
动态方法
通过运行与hook相结合的方式,可以让我们不去考虑去混淆的问题,直接找到OLE对象并将其进行保存就可以,而Denis O'Brien大佬的Silver Bullet方法给我了用运行和hook解决该问题的灵感和方法论。
本人所实现的hook是基于frida的,整体实现十分简洁,准备部分是由python实现的,hook部分是用js实现的,python部分没啥可说的,很容易理解,可以看一下frida官方给出的例子,以及DarunGrimUsing Frida For Windows Reverse Engineering这篇文章,且这篇文章写的非常精彩,它为我们提供了基于frida hookoffice宏指令进行有效处理的方法,值得学习。那我们来看一下hook的实现吧。
要想获取到OLE对象,OleConvertOLESTREAMToIStorage是关键API,我们来看一下Microsoft给出的详细解释,该API功能是将OLE对对象的格式从OLE1转换到OLE2,其中一定包含了我们想要的OLE对象信息。
因而我们可以hookAPI,并通过该API的第一个参数lpolestream(其是指向包含OLE1格式的OLE对象的指针)找到OLE对象,再根据存储结构找到OLE对象的具体位置及OLE对象的整体长度即可,具体操作请看Silver Bullet方法,大佬写的十分清晰且详细,复现非常简单,本文也不再进行过多赘述,hook的具体实现请看本人写的js代码,主要就是进行了获取并保存OLE地址和OLE长度的工作。
js代码如下:
通过复现Silver Bullet,我也发现了一个小问题,即通过API参数获取到的OLE对象地址(0x0A6A5B28),并未直接指向OLE对象的标识头(红框中十六进制字节),若直接根据地址和长度对该块内存进行dump,所获取的文件并不能直接传入本人所写的shellcode提取器,这是由于文件头的问题,导致oledump无法对该OLE对象进行正确解析,后续的操作也就无从谈起。
通过查阅frida文档,我发现可以用frida提供的内存数据匹配来实现精确拷贝,将OLE对象头作为匹配所用的模式串即可解决该问题。
js代码如下:
OOXML文件
OOXML文件其实是个压缩包,若其中存在OLE文件也仅能存在于activeX1.bin文件中,因而我们可以通过由Didier Stevens编写的zipdump来判断目标OOXML文件中是否包含.bin文件,若包含.bin文件则直接进入处理OLE对象流程中。
OLE对象
获取stream
先通过oleid获取所有maldoc的所用stream标签,该处实现还有优化的空间,可以将一维list改为二维list来存储stream标签,这样当maldoc中存在多级stream的情况时,结构更为清晰,不优化的话也可以,结果上不会存在太多差异。
检查stream
再根据获取到的stream标签,对maldoc中的每一个子stream都进行检查,通过xorsearch输出中的Socre值来判断对应子stream中是否包含shellcode,目前只去得分最高者进行后续操作。该处可以优化为:有得分即保留,都进入到下一阶段。
定位
这次我们将目光转向xorsearch输出结果的偏移值上,将出现的所有偏移值进行保存。
再利用偏移值和scdbg进行测试,确定shellcode的具体开始位置。
提取
scdbg可以判断出shellcode的具体位置,那我们通过cut-bytes对其进行精确切割,并将结果保存成文件。
scdbg不能确定shellcode的具体位置,则将整个子stream保存为文件,作为最终的shellcode
演示
动态获取RTFOLE文件
提供word路径,样本文件路径,以及hook脚本文件即可。
shellcode提取器
提供maldoc文件或OLE文件即可,以刚刚动态获取到的OLE文件为例。
对得到的shellcode(final_shellcode_file)进行一下简单的验证。
静态:可以看到其中有LoadLibraryWGetProcAddress,看到这俩函数可以确定,其在获取目标函数的地址,方便后续使用;又看到ExpandEnvironmentStringsW,可以确定其是将其中的“%APPDATA%”进行扩展;随后再调用URLDownloadToFileW来下载后续文件,写入指定路径中。
动态:选择scdbg进行模拟执行来获取更加准确的信息,通过shellcodedbg执行后的结果,可以更加清晰地看到,其调用了哪些函数,参数是什么,整体流程与上文通过静态分析得到的结果基本一致,但模拟执行向我们展示了准确的URL,以及从远端下载了什么。
可以看到通过两者结合我们快速且精确的得到了maldoc中的shellcode,并通过静态或模拟执行来获取到其主要行为,快速结束maldoc的前戏,将主要精力放在分析后续的主体行为上,提高效率,愉悦心情。
该工具目前只是一个雏形,逻辑较为简单,且可能存在不严谨之处,亦存在一定问题和优化空间,主要是提供一种从特例中提取特征,从而向普适化转变的思路,在此也十分感谢这些原始工具的创作者,在提供基础功能的同时,也给我了我很多向前的思路,希望可以像这些大佬一样,持续、高效的输出成果,做一点想做的事情出来。
一晃也正式工作快半年了,这个小工具也算是给我这段生活和2022交一份答卷了,想做的事情很多,也做了很多尝试,但因能力和精力原因有许多问题无法解决,导致了卡在半途难以向前,幸运的是有了做这个小工具的契机,也十分幸运的解决了大部分问题,并最终完成了它。也希望未来有机会和能力把那些没研究明白的东西整明白,再产出一些成果。
Reference
    运行环境基于 Remnux https://remnux.org/docker
    Didier Stevens https://isc.sans.edu/handler_list.html#didier-stevens)大佬的工具集及博客
    oletools 工具集(https://github.com/decalage2/oletools
    frida-python githubhttps://github.com/frida/frida-python
    frida 官方文档(https://frida.re/docs/home/
    Denis O'Brien 大佬的 Silver Bullethttp://malwageddon.blogspot.com/2018/11/deobfuscation-tips-rtf-files.html
    DarunGrim Using Frida For Windows Reverse Engineeringhttps://darungrim.com/research/2020-06-17-using-frida-for-windows-reverse-engineering.html


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-29 01:31 , Processed in 0.018162 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表