环境

此漏洞是在CVE-2017-11882补丁基础上触发的,所以需要把EQNEDT32.exe换成打了补丁的版本。微软的补丁下载地址不知为什么404了,我用的是这篇文章分享的文件。

分析

溯源

参考上一篇文章(本blog中的CVE-2017-11882分析)设置注册表、关闭aslr。

打开样本文件cve-2018-0802.rtf,跳过断点发现直接弹了计算器。

在winexec处下断点发现能断下

image-20200115153236493

通过调用堆栈找到00430c12处调用了winexec

image-20200115153414430

虽然通过其他公开的分析文章可以知道漏洞点在哪,但是还是尝试通过蛛丝马迹来寻找

此时继续往上追溯并不顺利,可能是在shellcode执行过程中把堆栈和调用栈搞乱掉了。

我的方法是根据堆栈和调用栈上的返回地址一个个试,比如下图中体现出来的可能是call 421c4b的过程中程序流程被劫持了,也就是说运行不到下一句了,于是我就在call和call的下一句分别打上“条件打印断点”。

image-20200115154113193

在断点页面编辑断点,使得在call的时候打印“start”,call之后打印“end"

image-20200115154540901

image-20200115154737216

重新打开一次,一直f9运行结束,查看log发现start和end都是成对出现的,说明不是421c4b

image-20200115154934716

按照上述方法,分别又试了421ff4、44c430、4214c6,发现只有call 4214c6的调用是没有返回的(这里的call只走到了一次)。

这里不要在4214c6里面下断点,因为call 4214c6的地方走到了一次,而4214c6自身可能被其他地方调用,可能在错误的时间点断下。

在call 4214c6的地方下断点,f7进去,用单步跳过的方法发现执行call 421774后程序跳到exec,那就继续调试这个函数。

函数较长,调试方法参考上篇文章

最后找到了是在函数421e39里面改变了421774的返回地址。发生的原因是没有检查第一个参数字符串的长度,而复制目的地是421774中的栈变量ebp-AC,复制长度过长就会覆盖返回地址。

image-20200115160802141

image-20200115161056176

调试这段复制过程会发现421774的返回地址只被覆盖了低位两个字节,从004214e2变成00420025,这么做是为了绕过aslr,而00420025地址处是一个ret指令,这就会把执行流程带到栈上。

image-20200115162731207

先是把esp减小了0x200(18f30c->18f10c),之后call 18f35e, 这个跳转使得ret没了,变成了inc ebx,程序继续往下执行,执行到jmp eax时eax指向winexec,后面就是弹计算器了。

image-20200115163526761

image-20200115163637277

shellcode分析

这段shellcode很有意思,仔细看看。

image-20200115182751529

  • shellcode从0018f350开始
  • 在0018f358处把esp减小0x200
  • 在0018f35A处有指令E8 FFFFFFFF,e8表示相对下一条指令地址跳转,这里即0xffffffff+0x18f35f=0x18f35e ,所以是call 18f35e (🙃这么做的作用是“自定位”,call会把下一指令压入栈中,后面就可以根据这个地址加上偏移来定位)
  • 18f35e处的指令是 FFC3, 被解释为 inc ebx,这样ret就被”吃掉了“,程序会继续向下执行

image-20200115183759067

  • 0018f360处pop ebx把call跳转之前的地址(18f35f)放入ebx中,注意在后面jmp eax之前压入的最后一个值是ebx+1c(18f37b),这是提前计算过的,恰恰指向那段cmd.exe命令

image-20200115192018368

  • 0018f361处把0压栈,作为后面winexec的第二个参数

  • 0018f362和0018f366处获取程序的基址。 FS寄存器指向当前活动线程的TEB结构,fs[30]是PEB结构地址(7efde000),PEB偏移8位是程序基址(400000)

  • 后面用基址加上0x30c12得到call winexec的地址

  • 0018f378处把”cmd.exe…“压栈

  • 运行到jmp eax的时候,eax指向call winexec的地址,参数也都正确。😘

此shellcode中通过相对寻址和自定位等技术,可以绕过aslr。经测试在开启ASLR后仍然能利用成功

image-20200115195708808

样本

使用 rtfobj cve-2018-0802.rtf -s 0 提取rtf中的ole object。

image-20200115193641701

格式说明参考上一篇文章

拖入010editor中查看,08是font name record,后面两个字节是record的标识符,不用关心,橙框部分就是shellcode

image-20200115194920301

参考