CVE-2010-3333 分析
文章目录
漏洞介绍
一个栈溢出漏洞,影响 Microsoft Office 系列的产品,包括 Microsot Office XP SP3, Office 2003 SP3, Office 2007 SP2, Office 2010 等多个系列。Word 在处理 RTF 格式文档的 pFragments 属性存在栈溢出,从而导致远程代码执行或程序崩溃。
实验环境
名称 | 版本 | |
---|---|---|
虚拟机 | VirtualBox | 6.1.2 |
系统 | Win XP | SP3 32位简体中文版 |
Microsoft Office | Office 2003 SP0 | 11.5604.5606 |
调试工具 | WinDbg | 6.12.0002.633 x86 |
分析工具 | IDA Pro | 7.3 |
分析漏洞成因
使用 MSF 生成 PoC
这里使用 Metasploit 生成的是 PoC,生成过程并不会嵌入shellcode,故目的是仅仅是触发漏洞,分析漏洞成因。生成过程如下:
-
搜索CVE并使用Exploit
-
设置Target
这里和正常的漏洞利用过程不太一样,Target list中有一项用于 Debug,我们在此选择该项。
-
生成 RTF 文件
栈回溯法
打开 Word,使用 WinDbg 附加到 Word。可以点击菜单 File –> Attach to a process, 或者直接按快捷键 F6,选择 WINWORD.exe 即可附加。
此时在命令窗口中输入"g"并回车或者直接按 F5,程序会继续运行,使用 Word 打开 PoC 文件 msf.rtf,此时程序会直接崩溃,WinDbg 的命令窗口中会得到如下的信息:
程序运行至模块 mso.dll 的地址 0x30e9eb88 处发生了内存访问异常,而当前执行的命令是:
|
|
即循环拷贝 esi 地址处的内容到 edi 地址处。在命令框中输入 !adderss esi 和 !address edi 来查看这两块内存区域的详细信息,可知发生异常时edi指向的内存地址 0x130000 所在的区域是只读的,故而发生异常。
重新按照之前的步骤 Attach 到程序,在命令窗口中输入 bp 0x30e9eb88 即可在触发异常的指令处下断点。下好断点后运行程序,打开 PoC 后程序在断点处停下。
分析此时的程序状态,我们可以得到一些结论。ecx 中存储复制的次数,由于此处一次拷贝一个 DWORD 也就是4个字节,所以实际拷贝的字节数为 4 * 0x322b = 0xc8ac,而断点前的一条指令正是该运算的逆运算,复制的字节数除以4以得到复制的次数。查看 esi 指向的区域如下:
|
|
回头分析一下 PoC 文件,以上两个寄存器的的内容都与此有关:
长度信息就在 PoC 文件 0x30的位置处,即 pFragments 的第三个字段偏移为8处。长度之后紧紧跟的就是拷贝进去的内容了。
再看看此时 edi 寄存器的值为 0x12a22c,ebp 寄存器的值为 0x12a23c,两者相差 0x10 字节,加上保存的 ebp,说明只要数据长度超过 0x14 字节,就会覆盖当前函数保存的返回地址,达到劫持控制流的效果。这里我手动修改了长度和内容,来验证以上的想法。将长度修改为 0x18,即刚好覆盖返回地址,同时选择一个比较显眼的字符,如全1。
可是以上的分析忽略了一些重要的事情,调试了一下午也也没有覆盖掉当前函数的返回地址。后来去查看函数 sub_30E9EB62,才发现该函数并没有自己的栈帧,即并没有保存 ebp,恢复 ebp 的操作。于是覆盖该函数的返回地址也就无从谈起了,只恨自己太菜。现在想想书上要去回溯调用栈,是要找到调用该函数的函数,继续分析。
再一次 Attach 到程序,在 0x30e9eb88 处下断点,运行,打开 PoC 文件。断下来之后在命令窗口中输入 kb 回溯调用栈。分析其中的项目的话,第一项是当前执行到的位置。输入命令 ub 加第二项的地址,结果的最后一行的 Call 指令的操作数即为答案。
重新运行,在以上得到的地址处下断,单步执行。发现 0x30F4CC93 处的Call指令会跳转到导致崩溃的函数内。
这个函数开始时开辟了 0x14 字节的局部空间,之前分析的写入的地址距离栈底 0x10 个字节是没有问题的,只不过栈底是这个函数的栈底。只要控制拷入的内容不过长覆盖到只读区域,就不会触发异常,就可以覆盖此处函数的返回地址,劫持控制流。
|
|
尝试构造新的RTF文件来覆盖EIP,这里长度随手写的,后填充14字节全零(两个十六进制数一个字节)。
|
|
运行至触发异常,可见 eip 真被覆盖成了 11111111。感觉离执行shellcode近在咫尺。
漏洞利用
将 eip 改成 jmp esp 或者 call esp 的地址即可跳转,此处我选择地址 0x0026762f。由于函数的返回指令为 retn 14h,返回的同时,esp 会变为 esp + 14,于是要在覆盖的 eip 后面填充 0x14 字节的数据进行填充。
这里又发现一个很坑的地方,对于填充的数据还有一定的要求,并非随意。ebp + 0x14 处会被检测,只要不是 0 就会触发异常,于是我选择拿全 0 填充。接下来在后面填充 shellcode。
使用 msfvemon 生成 shellcode,一个简单的弹出计算器的动作。指令如下:
|
|
将 shellcode 添加到 RTF 文件中,运行,却只见程序崩溃。换了好几个不同的也是崩溃,调试时shellcode确实是可以执行的,但总是出现异常。后来在网上找到看雪的一个分析贴,试了试其中的shellcode,可以执行(此处感谢看雪的 RNGorgeous 老哥)。
最终的 RTF 文件:
|
|
总结
此次分析比较令人遗憾,耗费了大量时间,最终没能执行shellcode。只能说明自己对于该漏洞的理解还是不够,而且缺乏很多技能如手撕shellcode之类的,还需努力。
参考
文章作者 Josephine
上次更新 2020-02-18