IIS6.0缓冲区溢出漏洞深度分析(CVE-2017-7269)

漏洞描述

开启WebDAV服务的IIS6.0存在缓冲区溢出漏洞可以任意代码执行,目前针对 Windows Server 2003 R2 可以稳定利用。在WebDAV服务的ScStoragePathFromUrl函数存在缓冲区溢出漏洞,恶意访问者通过构造以 If:

工具环境

windbg:用于附加w3wp进程进行动态调试

IDA:用于对httpext.dll进行静态分析

操作机:windows 2003

环境搭建

本次测试的系统环境是Windows Server 2003,首先需要开启WebDVA服务扩展

然后打开服务配置窗口,并启用WebClient服务 

漏洞测试

运行Process Explorer来监视当前进程

然后运行exp(exp在后面进行分析) 

通过构造以 If:

可以看到calc.exe进程已经创建,说明漏洞触发成功,用户名是NetWork Service,所以没有在桌面上直接弹出计算器。

为了后续使用Win调试W3wp进程进行调试,现在需要把calc.exe和python.exe进程结束掉

漏洞成因

使用IDA打开httpext.dll进行分析,在左侧函数窗口找到ScStoragePathFromUrl函数,然后看一下伪代码,看到qmencpy函数,参数v35表示复制的目的地址

查看对V35变量的交叉引用

可以看到v35由a3赋值,所以向目标地址复制这个操作实际是复制到a3所指向的地址上。而向上看Scstoragepathfromurl的函数声明,可以看出a3就是Scstoragepathfromurl函数的第三个参数。

漏洞源于memcpy操作,在复制时没有对复制的大小进行检查,复制的目的地址为a3,也就是调用该函数的上层函数传入的变量会被溢出。

漏洞分析

漏洞调试思路是一步一步逆向分析,从ScStoragePathFromUrl 函数到它的上层函数调用情况去分析

打开windbg,附加w3wp.exe 进程,首先要在Scstoragepathfromurl 函数开始的地方和v21=v35的地方下断点

在WinDbg中输入bp httpext!ScStoragePathFromUrl和bp httpext!ScStoragePathFromUrl+0x31e

输入bl查看下断点的情况

之后输入g让w3wp 进程继续运行,然后像之前那样打开exp,程序断在了ScStoragePathFromUrl函数的入口处 

输入g两次后来到第二个断点673f6f99 处,即第一个断点被中断了两次,说明在第一次被中断时,程序并没有进入memcpy 操作.

在第二次中断时才进入memcpy 操作。继续按F10来单步执行到673f6faf 处,这里就是执行第一个memcpy操作的地址

然后输入dc esi lecx来查看要复制的信息 

然后继续按F10单步执行到673f6fdb 处,输入dc esi lecx和dd edi lecx分别来查看要复制的内容以及复制目的地址范围。 

可以看到复制的内容为/aaa ... ,目的地址范围为0x6af828-0x6af948。

继续输入g来执行到下一次调用Scstoragepathfromurl 函数的开始位置,即673f6c7b处,然后输入g 来到673f6f99 后

继续按F10 单步执行到 673f6fdb 处。这时输入dc esi lecx来查看要复制的内容,再输入dd edi lecx来查看复制目的地址范围 

从结果中我们可以看到这次esi 指向的数据为/bbb ... ,目的地址范围为0x680312e4- 0x680318d4

同样继续输入g后在ScStoragePathFromUrl 函数中断下来,再次输入g,这次没有在673f6f99 处中断,而仍然是在ScStoragePathFromUrl函数中断下来,所以继续输入g后在673f6f99 处中断下来。

接下来按F10 单步执行到673f6fdb 处,输入dc esi lecx 来查看第三次复制的内容, 输入dd edi lecx 来查看这次复制的目的地址范围 

从结果中可以看出这一次复制的目的地址为0x006afad8-0x006afbf8

继续输入g ,程序在ScStoragePathFromUrl 函数处(673f6c7b)中断下来,之后按F10一直单步执行,注意到 call ScStripAndCheckHttpPrefix 函数处

在这里按F11单步进入,该函数的功能是检查url 的合法性,如果使用ida pro 来查看ScStripAndCheckHttpPrefix 函数 

可以发现674035f3 处有一个call dword ptr [eax+24h], 该处调用了IEcb 对象的0x24 偏移处指向的虚函数。

继续我们的调试,进入该函数后,按F10来单步执行到 call dword ptr [eax+24h] 处(674035f3),继续按F11进入这个虚函数调用

可以看到IEcb 对象的0x24 指向 68016082的位置,ecx 赋值给esp 以此来控制栈空间,当执行完ret 返回时,eip会被引导到了ROP 阶段,以此来绕过DEP 

继续F10单步执行,在单步的过程中可以发现有一连串由POP、RET等指令组成的ROP 链 

一直按F10,执行完ROP 后正式来到了shellcode 处(68031460) 

从以上的调试中可以发现,POC 通过覆盖IEcb 对象的0x24 偏移处的虚函数地址以此来控制eip ,进一步的使用ROP 来引导到shellcode

因为此漏洞为栈溢出漏洞,所以还需要在ScStoragePathFromUrl 函数的上一层函数调用处去观察,其中具体的溢出覆盖过程还要进一步分析。

在IDA Pro中查看ScStripAndCheckHttpPrefix() 函数发现IEcb 对象为该函数的第一个参数,而该对象同样是ScStripAndCheckHttpPrefix() 的上层函数ScStoragePathFromUrl() 函数的第一个参数。

下面我们要通过栈回溯找到调用ScStoragePathFromUrl 函数的上层函数,首先我们先依次点击WinDbg菜单栏的和。然后像之前一样在命令提示符窗口依次输入

接下来再用WinDbg 重新附加w3wp 进程,并在命令行内输入下断点,然后输入运行

然后运行exp 

发送数据触发漏洞,进程会在ScStoragePathFromUrl 函数入口处中断,这时我们输入kb来进行栈回溯,查看是哪个函数调用了ScStoragePathFromUrl函数 

从结果中我们可以看出 httpext!HrCheckIfHeader+0x124 处调用了ScStoragepathfromurl 函数。

使用IDA Pro 打开 httpext!HrCheckIfHeade r函数,可以看到在函数内共有两处调用了ScStoragePathFromUrl 函数,ScStoragepathfromurl 函数的第三个参数str 为栈上的单元,可以通过查看ebp-328 地址开始的内容来得到str 的内容。

按TAB 键再查看函数汇编代码,可以看到两处调用ScStoragepathfromurl 函数的指令地址分别为673f5445和673f547f 

这次在WinDbg 调试过程中需要关注ScStoragePathFromUrl 函数的第三个参数所指向的地址的覆盖情况。

像刚才一样,我们先点击WinDbg菜单栏的Debug->Break和Debug->Datch Debuggee,杀死calc和python进

再使用WinDbg 重新附加w3wp 进程,在上述两处调用ScStoragePathFromUrl 函数的地方及ScStoragePathFromUrl 函数的起始地址和函数内v21 = v35 处下断点,即分别输入

然后输入bl可以看出我们下断点的情况

之后输入g让程序继续运行,然后打开exp 

触发断点,之后程序在673f5445 处中断下来 

输入dd ebp-328查看 

此时ebp-328 地址的内容为0128f804 ,输入g继续运行,程序在ScStoragePathFromUrl 函数入口处(673f6c7b)中断, 继续输入g ,来到了第二次call ScStoragePathFromUrl 的地方(673f547f) 

根据程序上一步没有在673f6f99 处(v21 = v35处) 中断下来,可以判断出在上一次ScStoragePathFromUrl 函数里没有执行memcpy 操作。输入dd ebp-328查看该处的内容来验证 

可以发现ebp-328 处的内容并没有改变。 输入g 继续跟进并来到ScStoragePathFromUrl 函数的memcpy 操作处(673f6f99) 

按F10单步执行到 673f6faf 处,输入 dc esi lecx来查看复制的内容 

继续按F10 执行单步,来到673f6fdb 处, 输入dc esi lecx来查看要复制的内容 

接下来我们先输入dc edi lecx来查看复制操作前该地址空间的内容 

然后按F10单步执行后,输入dc 680312e4 l4c来查看该地址空间复制后的内容 

可以看到复制操作完成后 680312e4开始的地址已经被/bbb ... 数据覆盖。 输入g继续来到下一次call ScStoragePathFromUrl 的地方(673f5445) 

输入g继续来到下一次call ScStoragePathFromUrl 的地方(673f5445),此时输入dd ebp-328可以发现ebp-328地址的内容已被修改为680312c0 

输入!address 680312c0 来查看该地址的内存信息

可以看到该地址为可执行文件映像一部分的内存。 现在ebp-328地址的内容已经被前面的memcpy 操作修改了,而之前ebp-328 地址的内容为0128f828 ,所以我们输入dc 0128f828 l4c 来查看一下之前复制的内容 

可以清楚的看到在0128f90c地址(即ebp-328 地址)处 被修改为了680312c0。

所以再跟进ScStoragePathFromUrl 函数的时候,memcpy 操作是复制数据到堆上,而不是栈上,输入g 跟进,程序在ScStoragePathFromUrl 函数(673f6c7b)处中断而不进入memcpy操作

通过输入kb 来查看其上层函数,可以知道是CParseLockTokenHeader 函数调用了ScStoragePathFromUrl 函数 

继续输入 g 程序在673f6f99 处中断后,然后按F10单步执行到673f6fdb 处,此时复制的大小为0x17f,输入dc edilecx 来查看复制前的内容 

按F10单步执行一次后,输入dc 680312e4 l17f 来查看复制后的内容 

可以看到复制的内容为为/bbb ...

继续输入g,这次直接来到了ScStoragePathFromUrl 函数(673f6c7b),程序没有在Hrcheckifheader 函数里中断,通过kb 来回溯调用可知ScStoragePathFromUrl 函数被Cparselocktokenheader 函数调用。

继续输入g,又中断在673f6c7b,即ScStoragePathFromUrl 函数再次被 Cparselocktokenheader 函数调用,继续输入g来到673f6f99 处 

连续按F10单步执行到673f6fdb 处,可以看出此时要复制的目的地址为 0128fad8 ,复制的数据大小为0x4c。 先输入dc edi lecx来查看复制前的数据,再按F10单步执行一次后输入dc 0128fad8 l4c 来查看复制后的数据大小 

继续输入g, 程序在ScStoragePathFromUrl 函数处(673f6c7b)中断,输入kb 可知此时调用ScStoragePathFromUrl 函数的还是CParseLockTokenHeader+0x119 的地方, 由前面的调试我们可以知道,IEcb 对象的0x24 偏移已经被修改了 

按F10继续单步跟进, 遇到call ScStripAndCheckHttpPrefix(673f6cc4)时,按F11步入该函数,之后继续按F10单步执行,来到call dword ptr [eax+24h] (674035f3)的地方 

可以看到IEcb 对象的0x24 偏移处的地址为680313e4的数据被修改为了68016082这个地址。 按F11 继续步入,之后一直按F10 单步执行最后便可来到shellcode 处(68031460) 

分析可知修改来源于向堆地址复制数据所致,而shellcode 同样是在这一次被复制。 所以,之后的流程被控制了eip ,通过ROP 技术来bypass DEP, 最后进入到shellcode 去执行。

分析总结

CVE-2017-7269 漏洞属于溢出漏洞,原理依然是对复制的数据的大小没有作限制处理,导致可以复制任意长度的数据,其漏洞的利用使用了三次有效的memcpy 复制操作.

第一次复制操作为下一次复制到堆做好了准备,第二次复制操作将IEcb 对象0x24 偏移处数据覆盖,并写入shellcode 到堆中,第三次复制是成功调用IEcb 对象0x24 偏移的关键(这里没有去动态调试)。其执行流程将栈空间引入到堆空间,确保shellcode 可以了执行。

本文由看雪论坛 hackerbirder 原创

原文链接:https://bbs.pediy.com/thread-250744.htm

你可能感兴趣的:(IIS6.0缓冲区溢出漏洞深度分析(CVE-2017-7269))