关于CVE-2017-7269,网上的大神们的分析的都很有高度,我做为一个小白,拿着这种给了exp的漏洞,我没有想太多,直接windbg和IDA动静结合,调试进行分析,不过,这样可能造成分析有些片面,毕竟是纯逆向进行分析。
好了,首先说说。
环境Windows Server 2003R2 上开启WebDAV服务的IIS6.0。
工具 Windbg,IDA
接着修改网上的EXP代码我们现在不需要完美执行这个EXP,我们需要它崩溃,所以去掉作者添加的shellcode,只保留EXP部分,如下图。
现在进行调试,Windbg直接附加进程,上网查了查IIS的进程名称为W3WP.EXE,好的附加,然后g跑起来。接着把修改后的EXP运行。好了,如下图所示,它崩溃了。
退出Windbg,再次附加W3WP.EXE的时候,发现已经找不到这个进程了,这是IIS应用池机制的问题,解决办法有两个
[1]备份虚拟机镜像
[2]在IIS信息服务管理器里面把网站下的任意网站右键浏览一下,W3WP.EXE就会重新启动
接着进行调试,这个漏洞作者是给了漏洞函数的ScStoragePathFromUrl。使用IDA静态分析吧,那么dll是那个呢,作者并没写明dll名称,但是在IIS信息服务管理器开启WebDAV服务的时候可以知道,如下图。Dll名称为httpext.dll
我们直接把这个dll,放入IDA,加载其符号表。然后CTRL+P 查找函数,输入函数名ScStoragePathFromUrl。双击进行进行分析。
其中很有趣地方里面有明显的内存拷贝,而且有if判断,那么是简单的栈溢出吗?
If判断地址
我们继续进行动态调试,知道了dll的名称,我们先用sxe ld:httpext下加载dll时的断点。
通过IDA知道了ScStoragePathFromUrl这个函数的retn地址为0x673F702C,那我们直接在这个地址下断点,看看每次执行完这个函数时候栈返回地址是否被覆盖,但是不幸的是我尝试几次,返回地址没有被明显的直接覆盖,最后都会以崩溃掉。
好像直接观察堆栈并不能看出什么来,换个思路,完全从逆向的角度分析,先不断下断点定位崩溃函数,看函数崩溃的原因是什么。进过几次的断点后,定位到了ScStoragePathFromUrl内部的一个函数ScStripAndCheckHttpPrefix,这个函数代码如下。
没有错,这个函数调用了虚函数,那么这个洞是简单的堆溢出吗?
再次进行调试,这次进行大量的逆向数据记录,希望从数据的变化中分析出这个洞的成因到底是什么。
首先我们要确定一下我们的要关注的数据什么?(地址通过IDA得到)
[1]内存拷贝 代码地址 0x673F6F99
[2] 判断是否进行数据拷贝的代码地址 代码地址 0x673F6F55
于是windbg下断点,执行情况如下
可以发现这个数据拷贝并不会每次进入ScStoragePathFromUrl函数都会进行拷贝,而且拷贝次数只有3次,分别是第二调用ScStoragePathFromUrl函数,第三调用ScStoragePathFromUrl函数,第五调用ScStoragePathFromUrl函数(其实没进行拷贝的调用也很重要),好吧,既然拷贝了三次数据,那么就下断点进行查看到底拷贝了什么数据,对堆栈进行了什么的影响吧。
再进入windbg,只对内存拷贝进行下断点,并且每次跟完全部的拷贝,
第一次拷贝的结果如下(代码太多,不全部展示)
第一次拷贝的数据范围
edi 0130f804~0130f958
(第二次和第三次执行的时候edi的地址会大改,但是篇幅的原因,不能全部展示)
现在讲讲通过上面的代码再结合IDA,Windbg,我自己找到数据关系。
一共三次大内存拷贝,每次进行一次大内存拷贝时,有4次小拷贝,其中有两次不会拷贝,而另外进行拷贝的两次的地址edi是连续的,而esi是不连续的。
Edi的地址如果在某次大拷贝的时候变成一个对象的地址,然后进行拷贝,是不是就可以利用了呢?原作者也确实这么做了。
三次大内存拷贝的edi的地址变化范围如下:
第一次拷贝的数据edi:0x0130f804~0x0130f958
第二次拷贝的数据edi:0x680312c0~0x68031464
第三次拷贝的数据edi:0x0130fab4~0x0130fc08
通过数据好像看起来第一次和第三次好像是栈溢出。第二次是堆溢出
但是edi,esi的值是怎么被修改的,edi的值来自哪里?Esi的值来自哪里,这个问题需要弄明白。
通过IDA,和windbg,我找到了这些代码
通过看上面的第一次拷贝的范围可以知道,第二次开始的edi(堆地址)的来源地址0130f7a0,它并没有在第一次拷贝的范围内,但是这个地址就不能通过别的方法修改吗?
通过继续跟踪函数我找到了这条指令
当前的esp=0130f7a4,push也就是在给0130f7a0赋值
而ebp+0Ch =0x0130f7b8来自于
Edi来自于
跟到了这里原来数据来源是0130f90c,结合第一次拷贝的数据范围edi:0x0130f804~0x0130f958可以知道,这个地址就是拷贝进去的数据。(这里由于篇幅有限只分析,怎么通过第一次拷贝的数据,修改第二次将进行拷贝的edi的值,第二次的拷贝怎么修改第三次的edi值类推)
那么ESI是什么呢
通过几次再内存中的查看
[1]第一次拷贝前的esi指向的内存内容
[2]第二次拷贝前的esi指向的内存内容
[3]第三次拷贝前的esi指向的内存内容
可以知道esi的内容就只想我们发送数据的地址。
好了,我们现在能知道原作者通过第一次的溢出,使第二次的edi,变成自构造的对象堆地址,进行了第二次堆溢出,那么第三次溢出的作用是什么?
第三次拷贝的数据范围edi:0x0130fab4~0x0130fc08
下面这条指令是给ecx(this指针)赋值的,此时的ebp-14h=0130fbbc在第三次的溢出范围。而且结合第二次拷贝的数范围据edi:0x680312c0~0x68031464可以知道现在赋值的ecx就是第二次拷贝的起始地址。
//ecx值来源栈地址 0130f960内容 ->变成680312c0
接下来在执行虚函数时ecx已经是构造的exp的地址
进入之后发现虚函数的内容如下
把ecx赋值给esp,retn后,就从对象开始执行,并进行ROP,绕过DEP
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2020-2-4 13:05
被kanxue编辑
,原因: