*原创作者:gongmo(聚锋实验室)
注意:本分析一切结果均在win7 x86 sp1中尝试。
在微软的官方描述中如下:
如果 Microsoft Web 分布式创作和版本管理 (WebDAV) 客户端验证输入不当,那么其中就会存在特权提升漏洞。成功利用此漏洞的攻击者可以使用提升的特权执行任意代码。
若要利用此漏洞,攻击者首先必须登录系统。然后,攻击者可以运行一个为利用此漏洞而经特殊设计的应用程序,从而控制受影响的系统。
工作站和服务器最易受此攻击威胁。此安全更新程序通过更正 WebDAV 验证输入的方式来修复这个漏洞。
通过微软的介绍,此漏洞是一个限定系统的提权漏洞,因为此漏洞在win8或者更高的系统上是触发BSOD,而在win7及以下的系统中才能提权成功。所以微软设定此漏洞的安全等级为:中。虽然如此,我们还是应该引起重视,毕竟,可以获得管理员权限的漏洞危害性依然很大。
本文通过基础性的研究,大概的探究下了漏洞的修补前后和执行的过程,供大家参考。
在2016年2月9日发布的补丁中,微软修复了此问题。补丁名称为:Windows6.1-KB3124280-x86。后来通过对比这个补丁前后,发现微软在mrxdav.sys中增添了MRxDavIsCallerPrivileged函数并且修改了DAVFastIoDeviceControl和DAVDevFcbXXXControlfile的执行过程。
下图是对比补丁前后marxdav.sys执行的过程图。(红框为补丁版本)
1 )MRxDavIsCallerPrivileged函数主要通过调用SeAccessCheck函数验证进程的访问权限进行作用。这样任何通过fastio分发的函数和文件控制块控制的文件,都需要经过权限的验证,是否有足够的管理员权限执行,如若没有,则MRxDavIsCallerPrivileged函数返回false,然后调用失败的路线。
2 )其次在调用的历程函数中,MrxDAVEfsControl函数增加了对传入的device_object是否为null的验证。见下图红框所示缩略图:
放大图如下:
根据IDA的分析:
上图是补丁中通过验证MRX_SRV_OPEN+0×18对象结构体否为空,若不是NULL;则验证其MRX_SRV_OPEN+0×18+0xC对象,若文件对象正常,则验证其设备对象。如若出现一个为NULL;则转入失败,最后调用RxReleaseFcbResourceInMRx释放MrxFCB。
从整个函数推导来看:传入iofcalldriver函数的device_object来自:
Device_object=rx_context+0×38+0×18+0×10 (win7 sp1x86系统)
由于windbg中并没有找到此结构体,但是在windws driver kits中发现了此结构,在rxcontx.h头文件中,我们可以看到rx_context的结构体;以下是个人推导(仅对win7 sp1 x86来讲):
MRX_SRV_OPEN=rx_context+0×38;
MRX_FCB=MRX_SRV_OPEN+0×10;
暂用AAA表示此结构= MRX_SRV_OPEN+0×18;
DEVICE_OBJECT=AAA+0×10;
猜测为FILE_OBJECT=AAA+0x0C
通过windbg;我们查看到验证判断的过程device_object的过程;esi的值为rx_context结构体。 MRX_SRV_OPEN是bc4381f8;结构AAA为:9920f508;如下图:请依次对应。
验证判断过程如下图所示:首先去验证AAA结构是否为空,然后依次验证AAA+0x0C;最后验证AAA+0×10,即为: DEVICE_OBJECT。
在微软公布修补补丁的同时,黑客大神koczkatamas公布了漏洞源码程序。
漏洞原理:
在rdbss调用mrxdav的时候,利用rdbss!RxCreateRxContext创建了一个rx_context结构体的参数,而结构体rx_context默认的一个device_object对象初始化是null。而在内存中,null可以为0×00000000;所以只要作者精心构造一个以地址0×00000000为开头的device_object结构体,填充好MajorFunction对应函数的地址(用户的函数地址)。但是想要执行,还是需要调用IoCallDriver分发函数,而想调用到IoCallDriver分发函数,作者这里使用了NtFsControlFile作为触发进入mrxdav!MrxDAVEfsControl的条件从而调用到IoCallDriver。
所以在作者公布的源码中,申请了一块以0×00000000开头的内存;并且通过Marshal.Copy函数填写完整了device_object的结构体。如下图:
通过windbg;我们可以看到71c91150处就是shellcode的地址了。也是需要执行的地方。如下图:
例如:原函数IofCallDriver执行方式为:
driverObject->MajorFunction[irpSp->MajorFunction](DeviceObject,Irp );
修改后的函数执行为:
driverObject->shellcode(DeviceObject,Irp );
下图红框就是执行r3程序的地方。(调试的次数不一样,执行shellcode的函数地址也不同,下图shellcode的地址是:6ae91150。)这样,就从内核执行了任意r3的函数,成功将系统的Token赋值给应用程序eprocess的Token,达到提权的目的。
通过初步漏洞分析,才发现windows的博大精深。本漏洞没有通过覆盖,溢出等方法寻找突破点,而是利用了内存中NULL可以理解为0×00000000的方式,去构造漏洞。同时应对漏洞问题时候,如何以最小的改动来换取最大的安全。微软做的这点值得我们去学习思考。
*原创作者: gongmo(聚锋实验室),转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)