漏洞描述
开启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