1. 前言
前几日,笔者在exploit-db上发现了一个kill.exe的溢出漏洞,在众多的UAF漏洞中,这种单纯的溢出漏洞简直如一股清泉一般,遂将其捡了出来,深入地看了看。
原计划写一个完整的可用EXP,但貌似失败了。所以,这里以半介绍半讨论的形式聊一聊这个EXP的问题。对于在这方面比较有经验有见解的读者,笔者诚恳的请求不吝赐教;而对于这方面不太了解的读者,希望这篇可以把一些基本信息介绍给大家。
2. 漏洞分析
Kill.exe是微软发行的Windows调试工具包的一个小工具,用于终止一个或多个进程,以及它们的所有线程。在exploit-db中提到的包含漏洞的kill.exe的版本号为:6.3.9600.17298。在安装Windows Driver Kit (WDK)8.1时,会自动安装该版本的kill.exe工具。
此外,在6.1.7650.0版本的kill.exe工具中,同样存在类似的问题。该版本的kill.exe工具可以通过安装WDK 7.1获取。
下面首先分析一下6.3.9600.17298版本的kill.exe的漏洞函数。Kill.exe在处理命令行参数时触发了栈溢出漏洞,可以向栈内写数据:
该漏洞函数的内部逻辑也较为简单,当只接受到一个参数时,可以概述为:
当有多个参数时,用一个循环把上述内容进去,即针对每个参数判断是否为数字然后进行相应操作并保存结果。需要注意的是,原函数的内容要比这种表述复杂的多,该图只是示意图,用于帮助读者理解该函数的所做工作。
下面仔细说明漏洞函数的两个分支:左侧分支代表接收到了一串数字字符串为参数,则计算该字符串所代表的数值。其中,v1为字符串起始地址,v7为最终的计算结果。48为’0’的ascII码值,*10表示乘以权重。右侧分支表示接收到了一串字符串,则将字符串内容复制到栈上。其中,v1为字符串起始地址,v5为指向某栈空间的指针。
如果仔细研究的话,可以发现在左侧分支中同样存在一个漏洞:v7存在整数溢出漏洞,汇编代码如下:
上部分用于判断字符串的下一位是否为数字,下部分用于计算其数值。显然,EAX存在整数溢出的问题。但是,这漏洞并没有什么用。恭喜你,获得“认真的代码阅读者”成就。
下面着重看右侧分支也存在一个漏洞,即栈溢出漏洞。其执行复制操作的汇编指令如下:
图中的3次判断的含义为:该字符是否为空格,是否为制表符,是否为空,如果是则终止复制;否则继续复制下一个字符。
当笔者以长串的’A’作为其参数启动kill.exe之后,可以观察到栈被覆盖的情况:
3. EXP讨论
与Win XP相比,Win 7环境更加复杂多变,所以本节将EXP相关的讨论放在Win XP环境下。首先,将kill.exe程序复制到Win XP的虚拟机中,然后考虑漏洞的利用方法。
粗略的归纳一下,常见的栈溢出漏洞的利用方式有3种:
1. 覆盖函数返回地址。
2. 覆盖SEH结构。
3. 覆盖其他有用数据或关键数据,如对象以及虚表指针等。
下面开始分开讨论kill.exe的情况,并试图找出可行的可用方式。
3.1 覆盖返回地址
在WinXP环境下,覆盖返回地址当然是一种简单可靠地利用,但是这里存在一个问题:kill.exe是有stack cookie保护的,即有/GS标记:
自然而然地想到,有没有办法过掉这个stack cookie。首先,可以肯定的是,这个cookie并非是静态的值。进一步的,有些文献表示可以计算或猜测这个cookie的大致取值范围,以减少/GS的保护能力,但在这里不打算选用这类方法。最后,由于kill.exe中的栈溢出漏洞只能覆盖部分栈中的内容,无法覆盖到位于.data段中的数据,所以修改cookie值也是不可行的。
无奈之下,只能选用覆盖SEH结构的利用方法,当然这也是一种有效绕过/GS保护的EXP方法。
3.2 覆盖SEH结构
覆盖SEH结构同样是一种颇为有效的利用手法。但是这里同样存在着一个问题:kill.exe是有Safeseh保护的,即有/Safeseh标记:
此外,图中还可以发现kill.exe开启了CFG保护,即有/guard:cf标记。但是由于笔者的分析环境是winXP系统,所以暂时不考虑CFG保护。
因为存在Safeseh保护,所以EXP变得更加麻烦。绕过Safeseh保护最好的方法,就是不使用覆盖SEH结构的EXP技巧,而是直接去覆盖函数返回地址或其他关键栈数据,而这显然是不可行的。考察被kill.exe加载的其他模块,发现全部都有/Safeseh标记,这就使得通过未启用/Safeseh的模块绕过Safeseh变得不可行。
不过,需要明确一点,kill.exe在win7环境下是自动开启DEP和ASLR的,截图如下:
而在winXP环境下,并没有开启DEP:
至于为何在winXP环境下,并没有开启DEP的原因,笔者并没有考证。
暂不考虑未开启DEP的原因,既然kill.exe没有开启DEP的话,那么只要保证异常处理函数不在任意模块之中,且不在栈中,那么就可有效的绕过Safeseh。下面,笔者尝试用该方法过掉Safeseh保护。首先,观察进程空间内不属于任何模块的地址空间:
以上地址都是不可取的,原因如下:如果打算让kill.exe触发异常处理函数,必须赋值很长的数据导致向栈之后的不可写地址写入数据,那么所有的写入内容不能包含空格、换行符以及空字符。而以上所有这些地址的最高位字节均为0×00,这个字节将终止栈的覆盖过程,原因见第1节中的分析。
此外,还有另外一小部分不属于任何模块的地址空间:
在这一部分地址空间中,可以用metasploit中的工具查找pop pop retn指令串,其结果如下:
当笔者尝试使用这些地址的时候,发现这些地址无法与ASCII码或者GBK码对应。这里捎带一提,kill.exe是可以接受GBK编码的字符(简体字、繁体字等),虽然这可以扩大可用的字符数量,但并没有什么帮助。
3.3 覆盖其他关键数据
可以观察从覆盖起始点,到stack cookie之间的所有栈空间,并未发现任何有价值的关键数据,即便将其完全覆盖成错误数据,程序也是可以正常运行,并在退出漏洞函数时清理了包含错误数据的栈空间。
到此为止,笔者并没有找到有效的EXP方法,暂时决定先搁置此版本的kill.exe,下面开始考察其他版本的kill.exe工具。
4. 另一个版本的kill.exe分析
在第1节中,笔者提到了另一个版本的kill.exe工具,该版本的kill.exe工具同样有GS和Safeseh标记,无DEP,但也没有guard:cf标记。
此版本的kill.exe工具在栈溢出时的关键代码与第2节分析的内容略有不同,如下图所示:
上图中,关键的变量名已经标出,分别是source、temp和destination,这三个变量的含义正如其名称所示。
此版本的kill.exe在溢出时,会覆盖destination变量,从而使得可以对覆盖的内存地址和内容进行很小限度的控制。但这是否可以导致有效的EXP,就留给有兴趣的读者自己分析吧。
5. 结论
按照本文的分析结果来看,Microsoft的各种安全机制已经非常成熟,非常可靠,在这诸多的安全防护机制之下,MS的产品即便存在一些漏洞,也无法实现其有效利用,尤其针对传统的简单单一漏洞。当然,在更复杂的情况和环境之中,通过多个漏洞组合或者其他逻辑上的错误漏洞,也确实存在一些可被利用的漏洞。而对于非MS产品,那就另当别论了。
此外由于笔者知识有限、才疏学浅,笔者个人无法实现有效的EXP并不代表其他分析人员同样无法实现,在这里笔者由衷地期待能够得到这些高人的指点。对于不太熟悉本文内容的读者,希望这篇能带来一些启发和帮助。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/55789.html