把梦想放飞在蓝色的天空里...

看似寻常最奇崛,成如容易却艰辛--王安石

MS11-021Excel缓冲区溢出漏洞分析

      在看雪上面的链接地址:http://bbs.pediy.com/showthread.php?t=144387

好久没分析过漏洞了,上个星期师兄发了一个Excel漏洞分析的博客链接(Here),浏览了一遍。博主也是看了一篇国外的博客自己调试了一遍,写下了收获心得。觉得作者的分析方法很好,有借鉴之处,故决定亲自动手分析一下,或许会有新的收获。。。

       先把环境搭建好,我的调试环境是XP sp3 + office 2007 sp2 + ms10-080补丁。在老外的博客上将原始POC和python文件DOWNLOAD下来,开始了调试之旅。把POC在调试环境下用EXCEL打开,程序跑飞了。打开OD调试器,EIP指向了一个错误的地址(0x414d4ed5), 虽然我的环境跟作者所说的相同,但是在调试的时候还是存在差异,所以只得自己摸索了。按照作者的方法,我在栈里苦苦寻找,却没有发现一个指向溢出函数空间的地址。既然不能按原作者的思路在栈里寻找蛛丝马迹,那么我该怎么下断呢?灵光一闪,原作者说是一个memcpy函数向栈中拷贝数据,覆盖了函数返回地址导致溢出,于是我下了断点:bp memcpy,可惜数据都完全复制到了栈里,OD却眼铮铮地看着它复制。。。百思不得其解~抓狂但是我并没有就此放弃,相信柳暗花明的时刻会来的!

       晚上再次进行调试攻坚,当我再次打开POC的时候却出现了和上一次不同的异常。

图一  向非法地址写数据。

图 二 原函数的EBP和返回地址被覆盖了

       艾,奇怪了,难道EXCEL解析方法变了吗?仔细观察一下现场,栈里出现了大量的可疑数据,菜鸟都可以看出是老外精心构造的数据。

那出现异常是在返回前还是在返回后呢?此时我猜想该异常应该是在返回前,因为原函数的EBP和EIP都被覆盖了。查看一下SHE链,发现第一个异常处理节点还在很远的地方:

看来异常处理结构还是完好无损的。理论上可以通过覆盖异常处理地址来达到利用的目的,只是需要写入的数据较多。

我想先分析一下漏洞的触发原因。

这时候对EIP出现的位置有两种解释(假设异常函数为A):

1.  函数A在向栈里复制数据后还没返回,出现了异常。(这时候可以向上寻找是否有strcpy和memcpy之类的函数)

2.  函数A在向栈里复制数据,返回地址覆盖不精确,导致函数A执行完后成功返回,这个时候栈里的数据全被破坏,出现异常也是理所当然的了。

仔细浏览异常点上方的数据,没有找到类似strcpy和memcpy之类的函数。初步排除了第一种可能。

先碰碰运气看是否是当前函数向栈里复制数据,在函数开始的地方下断,开启新一轮调试。

果然OD断在了0x301a0b7c。这个时候栈里的数据还是完好的,说明向栈中复制数据是在0x301a0b7c之后。再往下跟踪,并时时观察栈里的数据。在执行完函数

后,栈里出现了“覆盖”数据。于是我们断定源作者写的poc在我的环境下没有利用成功,导致函数返回后,读取破坏的栈内的数据导致异常,不信往下看。在地址

0x301a0c66处读取栈内数据,其值刚好是0x51495745。导致了前面我们所述的异常。

在0x304D4ED0处再设一断点,一探究竟。运行至0x304D4ED0,单步跟进,在内存窗口监视函数返回处的堆栈地址。当执行完函数

后堆栈里的数据就被覆盖了

单步跟进这个函数,发现在里边有一个memcpy函数,

其目的地址为0x1370af,长度为0x300。

在memcpy之前,并没有对长度检查。源作者的本意不是覆盖函数0x30199e55的返回地址,而是函数0x3053f626的返回地址。

从栈里数据可以看出,覆盖点是在0x3053f626的返回地址的下方8字节处(准确的说应该是7 字节),这个偏差导致了利用失败。

         再来看看目的地址是从哪里来的!从memcpy的上头可以看出目的地址是函数0x30199e55的第一个参数。再看看函数0x30199e55的参数又是怎么来的。从图中可以看出ebx是它的第一个参数,以下显示了ebx的来历。

3053F849    8B8D 24F1FFFF     mov ecx,dwordptr ss:[ebp-EDC]  ;0x0C0F

3053F84F    0FAF8D 00F1FFFF    imul ecx,dword ptr ss:[ebp-F00]   ;4

3053F856    8BF8              mov edi,eax                  ;0x300

3053F858    8B85 20F1FFFF      mov eax,dword ptr ss:[ebp-EE0]  ;0x134070,一个栈地址

3053F85E    8D5C01 03         lea ebx,dwordptr ds:[ecx+eax+3]

从以上汇编码可以看出:ebx = 0x134070 + 0x0c0f*4 + 3 = 0x1370af。而0x0c0f是源作者python利用脚本里的一个字段。从这里可以看出,0x134070是不可控的(如果可控的话,此poc应该可以在我的电脑上弹出计算器了),但是我们可以通过字段0x0c0f来调整覆盖的起始点,达到精确覆盖的目的。通过观察堆栈,函数0x30199e55的返回地址在栈中的位置为:0x134064<x0134070,难怪老外不选择覆盖函数0x30199e55的返回地址而瞄准了外边函数0x3053f626的返回地址。现在让我来改变0x0c0f的值,在我的电脑上弹出计算器。如下计算:0x134070 + X * 4 + 3 = 0x1370a9,X= 0x0c0d.

改变一下脚本里的值,果然弹出了计算器。

虽然弹出了计算器,但是我还想从更深处挖掘一下。0x134070的值到底可不可控呢?如何才能提高利用的成功率呢?于是请出了分析利器IDA,方便我们更准确地分析漏洞。通过IDA分析发现0x134070是函数分配的一个数组的一个元素的地址,是不可控的。我们只能通过动态调试的方法确定某个返回地址和该元素地址之间的距离来确定那个值。至于提高成功率刚开始我个人的想法是用同一个跳转地址从返回地址更低的地址开始(缩小0x0c0fd的值),多覆盖几个,这样如果函数的返回地址在栈帧上移动也可以成功跳转;但是后来突然想到作者说的绕过了GS,我回过头去检查一下函数0x3053f626里头的汇编码,果然存在GS,

这样说来我想的那个方法必须在返回前触发异常,数据还必须覆盖SHE才能利用SHE绕过GS。前面说过了,离第一个SHE节点还有一段相当长的距离。在诸多不稳定因素的情况下,这样可能情况更糟。

此漏洞形成原因还可以在深挖下去,源作者说Record的长度必须是0x400,读者可先去查看一下excel文档格式,动态调试下record的每个字段必须满足什么条件才能到达漏洞函数。这就留给肯钻又好学的你了。。。

总结:

1.原本我们可以覆盖0x30199e55的返回地址,可是“基址”0x134070在它之后,我们只能覆盖0x134070之后的区域。

2.想要快速到达案发现场,还有一种更简单的方法就是在被覆盖的区域内随便挑选一个地址,下内存写入断点。这样就不必一层一层地跟踪了。慢慢地在实践中我们领会了“下断”是调试的灵魂。一个恰到好处的断点可以为你节省宝贵的调试时间。

3.关于memcpy,为什么我在OD里下memcpy的断点却断不下来呢?这是因为OD默认下的是msvcrt.dll的memcpy,而此处的memcpy处在msvcr80.dll中。如果这样下断的话就OK了:bp msvcr80.memcpy。

4. 在调试的时候OD会有一些奇怪的问题,在调试的时候,如果点一下左上角的叉,再打开EXCEL--〉ATTACH—〉运行,你会发现EXCEL窗口没反应。这时候只能重启OD或者点击重新运行,再附加EXCEL。

5.经验是不断积累的,只有不断的自己动手去实践才会有提高!

 

阅读更多
个人分类: 漏洞分析
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭