查看原文
其他

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

hackerbirder 看雪学院 2019-05-25


漏洞描述

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



工具环境

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

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

操作机:windows 2003



环境搭建

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




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





漏洞测试

运行 Process Explorer 来监视当前进程。




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




通过构造以 If:<http:// 开始的较长header头的PROPFIND请求打开了计算器 




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


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


taskkill  /im calc.exe  /f<br>taskkill  /im python.exe  /f




漏洞成因

使用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菜单栏的和。然后像之前一样在命令提示符窗口依次输入:


taskkill  /im calc.exe  /f<br>taskkill  /im python.exe  /f


接下来再用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 处下断点,即分别输入:


bp httpext!ScStoragePathFromUrl,

bp httpext!ScStoragePathFromUrl+0x31e,

bp httpext!HrCheckIfHeader+0x11f,

bp httpext!HrCheckIfHeader+0x159。


然后输入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 可以了执行。





- End -





看雪ID:hackerbirder          

https://bbs.pediy.com/user-823237.htm



本文由看雪论坛 hackerbirder 原创

转载请注明来自看雪社区




热门图书推荐

 立即购买!





热门文章阅读

1、API监控+代码乱序的壳

2、Tcache利用总结

3、看雪课程 |  LLVM 编译框架详解

4、SandHook 第四弹 | Android Q 支持 & Inline 的特别处理




公众号ID:ikanxue

官方微博:看雪安全

商务合作:wsc@kanxue.com



↙点击下方“阅读原文”,查看更多干货!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存