0x00 前言
这一篇介绍一种比较特殊的漏洞,DoubleFetch,本质上说,这也是条件竞争(Racing Condition)漏洞的一种。
实验环境:Win10专业版+VMware Workstation 15 Pro+Win7 x86 sp1
实验工具:VS2015+Windbg+KmdManager+DbgViewer
0x01 概念
竞争条件(Race condition)是由于多个对象(线程、进程)同时操作同一资源,导致系统执行违背原有逻辑设定的行为。此类漏洞在Linux或者内核层面比较常见,当然在Windows或者Web层面也存在。尤其是一些电商网站,加入购物的竞争条件漏洞存在,则可能导致以低价购买多个商品。
了解同步知识的小伙伴应该不难理解,类比操作系统的RAW/WAR/WAW。
下面引用泉哥《漏洞战争》中的小例子:A、B两人同时向一个银行账户存款,此时卡上余额为1000元,其中A存款200元,B存款500元,正常的存款流程如下,两人存款后余额应为1700元。
用户A | 用户B | 余额 |
---|---|---|
检查余额 | 1000元 | |
存入200元 | 1200元 | |
检查余额 | 1200元 | |
存入500元 | 1700元 |
但是如果银行没有很好的同步处理机制,那么可能造成下面的情况,造成最终存款余额为1500元,丢失200元,这是很严重的问题。
用户A | 用户B | 余额 | 注释 |
---|---|---|---|
检查余额 | 1000元 | Time of Check(A) | |
检查余额 | 1000元 | Time of Check(B) | |
存入200元(丢失) | 1200元 | TIme of Use(A) | |
存入500元 | 1500元 | Time of Use(B) |
检查余额的时间可以称为“Time of Check”,存款的时间可以称为“Time of Use”,则该问题可为“TOCTOU”或者“TOTTTOU”,属于竞争条件漏洞。
此类漏洞常见于各类IO操作,如文件操作、网络访问等。
如果攻击者能在某个对象的Time of Check和Time of Use之间争得时间,在此时间内获得操作的机会,那么就有可能破坏程序原定的处理逻辑。比如相对用户B来说,TOU(A)就是对其的破坏行为,使得本应存入的200元被丢弃;同理相当于与用户A,TOU(B)就是对其的破坏行为,只是检查余额是个无害行为,假如它刚好也是个存款行为,那么这笔钱也会被“无效掉”,如下所示,我们将用户B的行为互换,存入的500元也会丢失。
用户A | 用户B | 余额 | 注释 |
---|---|---|---|
检查余额 | 1000元 | Time of Check(A) | |
存入500元(丢失) | 1500元 | Time of Use(B) | |
存入200元 | 1200元 | Time of Use(A) | |
检查余额 | 1200元 | Time of Check(B) |
熟悉编程的小伙伴应该知道互斥锁、自旋锁、信号量等概念,他们的出现就是为了解决同步问题,保证某一对象在对特定资源进行访问时,其他对象不能访问操作该特定资源,保证正常同步操作处理。
实验环境:Win10专业版+VMware Workstation 15 Pro+Win7 x86 sp1
实验工具:VS2015+Windbg+KmdManager+DbgViewer
0x02 漏洞原理
首先,看下IDA中,驱动程序流程:
注意到 IrpDeviceIoCtlHandler派遣历程中,loc_156BF跳转至我们的漏洞函数,我们找到引用:
ecx为我们的IO控制码,那么稍微推理一下,ecx大于0x222027,小于0x2223B,再往下,可以看到其精确等于0x22202B+4+4+4=0x222037。我们验证一哈:
1 | #define FILE_DEVICE_UNKNOWN 0x00000022 |
进入漏洞函数,我们看一下流程:
esi为唯一参数,取出参数变量地址+4处成员,与0x800比较,现在看起来好像没有什么问题,但仔细一想,好像和之前不太一样,少了一个参数,那么如果当前参数为用户缓冲区地址,那么大小怎么来确定呢,而取出来的成员又是什么呢?如果成员是缓冲区大小,那么多线程的情况下,多次调用DeviceIoControl改变此成员的值,就有可能绕过缓冲区长度检查,形成漏洞。下面是DoubleFetch.c文件中的漏洞函数。
1 | __declspec(safebuffers) |
可以看到,用户层的传来的参数为UserDoubleFetch,发现其结构为
1 | typedef struct _DOUBLE_FETCH |
那么,和我们的猜想是一致的,构成DoubleFetch漏洞。
0x03 漏洞利用
结合前面的分析,我们使用多核测试环境,注意这是必要的。(开始测试时,使用的单核Win7虚拟机,怎么测试都不成功,看了下源码,才发现代码中是有多核条件限制的)。
1 | SYSTEM_INFO SystemInfo; |
整理一下思路,我们通过多线程对要传入内核的用户模式缓冲区的size进行修改,在第一个竞争线程的Time of Check时间和Time of User之间,翻转线程在ring3修改size值,第二个竞争线程重新传入内核,即越过长度检查限制,从而造成缓冲区溢出,实现漏洞利用。
具体代码参考这里,下面给出两个线程代码:
1 | DWORD WINAPI FlippingThread(LPVOID Parameter) |
发现关于缓冲区溢出的内核漏洞,VS环境下编译的版本均有问题,测试第二版,可以看到提权成功。
0x04 漏洞反思
关于如何防范和检测此类漏洞,暂时还没有很好的想法。不过这几天在泉哥博客看到j00ru大佬之前开源的工具平台bochspwn可以实现对内核double fetches的监测 ,另一个版本的bochspwn-reloaded可以检测检测未初始化漏洞导致的内核信息泄露 ,后面研究下。
0x05 链接
jooru:Kernel double-fetch race condition exploitation on x86 – further thoughts