介绍
许多大型组织使用Windows部署服务(WDS)在网络中的新计算机上安装自定义操作系统。从本质上讲,Windows部署服务通常可通过LAN端口连接的任何人访问,并提供相关软件。它们确定操作系统以及每个新网络元素的附带程序和服务。
有了这种可访问性,如果恶意行为者能够破坏该服务器并对其进行修改以控制每台新计算机的内容并装备自己的专有恶意软件,则可以自然地考虑会产生什么后果。
在本报告中,我们将讨论我们对WDS基础设施的研究以及我们利用其漏洞的尝试。
Windows部署服务
WDS是Microsoft针对基于网络的Windows操作系统安装的解决方案。WDS使用磁盘映像,特别是Windows映像格式(WIM),并且自2008年以来作为服务器角色包含在所有32位和64位版本的Windows Server中。
WDS是一个复杂的系统,我们远远不了解它的整个运作。但是,对于本研究的范围,我们分析了WDS在新安装过程中的表现,因为这种预认证协商似乎是一种很有前途的攻击向量。
在提供完整的Windows映像之前,WDS必须提供一些网络启动策略。为此,它使用PXE(预引导执行环境)服务器。PXE是由英特尔创建的标准,它在引导固件中建立一组通用的预引导服务,最终目标是使客户端能够执行网络引导并从网络引导服务器接收网络引导程序(NBP)。为了传输NBP,PXE服务器使用普通文件传输协议(TFTP)。
TFTP是一种简单的文件传输协议,使用众所周知的端口号69在UDP / IP协议之上实现。由于其设计简单,TFTP可以通过小占用码代码轻松实现。因此,它是任何网络引导策略(如BOOTP,BSDP和PXE)初始阶段的首选协议。但是,TFTP缺乏更强大的文件传输协议提供的大多数高级功能。例如,它无法列出,删除或重命名文件或目录,也没有用户身份验证。相反,该协议仅支持读写。今天,TFTP很少用于互联网传输,其主要用途来自局域网内部。所有这些使它成为我们目的的有希望的协议。
起初
我们的第一个任务是使用Boofuzz创建一个TFTP哑模糊器。
Boulzz是Sulley模糊测试框架的继承者,它提供了一个简单的设置和优秀的文档,并且由于简单的Boofuzz语法,将相关的RFC转换为模糊脚本是一项相当简单的任务。
Tftp.py定义协议语义和要模糊的字段。由于这个模糊器非常通用,因此可以重新定位此代码以模糊任何其他TFTP实现,并且我们鼓励其他研究人员这样做。
当fuzzer运行时,我们手动反转了wdstftp.dll中实现的服务器。因为这两种方法往往相互补充。
wdstftp.dll
当我们颠倒dll时,我们开始检查CTftp :: ParseRequest中实现的文件读取机制。如前所述,该协议没有实现太多复杂的功能,因此这个表面是一个合理的起点。
TFTP读取请求(RRQ)在CTftpPacket :: ParseRequest中处理。验证PXE基目录中存在的请求文件后,将其读入CTptReadFile :: CacheBlock结构。
图1: CacheBlock Struct
这些CacheBlock在链表中管理。
ReadFile是异步由服务器进行 CTptReadFile :: _ IOCompletionCallback指定为自己的回调函数。
图2: ReadFile回调
到现在为止还挺好。但是,我们注意到了一种相当奇怪的行为。似乎CacheBlock的链表大小有限......两个节点?
在下图中,我们可以看到当缓存块的数量超过2时,尾部被删除。
利用我们新发现的TFTP协议知识,以及blksize和windowsize选项的使用,我们应该能够在接收到确认数据包之前制作一个将填充两个以上缓存块的请求。如果一切顺利并且时机正确,则在回调函数CTptReadFile :: _ IOCompletionCallback使用之前释放缓存块。
准备好,设置(页面堆上),去吧。
我们可以看到RAX现在指向释放的内存(!),有效地为我们提供了Windows部署服务中的Use-After-Free漏洞。
这个错误看起来相当微不足道,为什么我们的模糊器错过了呢?
答案是Sulley框架一次模糊一个字段,我们要求的读取时间从未如此长。这对于未来的模糊测试者来说是一个很好的教训:一方面,您希望您的数据包足够有效,以便解析器不会拒绝它们。另一方面,如果你使它太有效,你会错过潜在的错误。
开发方法
由于这是一个可远程触发的,未经过身份验证的高权限Windows服务器错误,因此我们绝对可以将此标记为严重漏洞。
通常,在利用免费后使用(UAF)错误时,我们会尝试在不同的状态下分配不同的对象(类似大小)或类似的对象,并在它们之间造成某种混淆。
寻找允许我们分配适合释放区域的对象的分配原语,我们检查了进程堆。
事实证明,WDS实际上使用了几个堆,我们的堆在wdstftp.dll,wdssrv.dll和wdsmc.dll之间共享。
虽然wdstftp.dll允许一些非常灵活的分配,例如TFTP错误数据包中的分配,但它们都是转换为Unicode的ASCII。
Unicode POC图6
这对于POC来说是一个很好的原语,但是伪造一个功能有效载荷会花费更多,因为我们需要取消引用一些指针。
下一个分配原语机制候选者是wdssrv.dll。它公开了一个RPC接口,可以远程调用WDS服务器提供的服务。
该协议的二进制性质似乎很有希望。
寻找任何攻击者可控制的分配,我们达到了CRpcHandler :: OnRecvRequest。
顾名思义,这个RPC处理程序在将RPC请求插入队列以供将来的工作人员处理之前对RPC请求进行初始解析。因此我们仅限于处理程序本身。
要使用释放的内存,我们需要使用相同的堆桶(大小为0x5c-0x78)。
我们在有些受控大小的处理程序中的唯一分配是CMemoryBuffer :: Initialize。
图7: RPC分配原语
以下脚本允许我们执行适合目标存储桶的成功分配。
图8: RPC POC
然而,显然一些结构,最重要的是CacheBlocks callbackCtx指针,保持不变(并且未初始化)。
图9:使用RPC POC的内存布局
如果我们扩大RPC负载,由于CMemoryBuffer :: Initialize执行的大小计算,我们将被分配到错误的存储桶。
我们的下一个想法是看看我们是否可以使用我们能够改变的CacheBlocks字段来升级事物。
不幸的是,进一步的逆转表明CTftpReader并没有真正使用它们。太糟糕了…
对于我们最终尝试利用此错误,我们尝试了不同的方法。我们尝试重新利用该错误并使用它从服务器获取重要的信息泄露。在标准情况下,IOCompletionCallback叫上充满了该文件的内容的CacheBlock,并将其内容发回给我们。通过混淆服务器并植入尚未填充文件内容的“新鲜”CacheBlock,我们希望服务器向我们发送新的CacheBlock的未初始化内存,从而导致重大信息泄露。
结论
WDS是一种流行的Windows服务器服务,广泛用于安装图像分发。它的底层PXE服务器有一个关键的远程触发使用后免费bug,可能被未经身份验证的攻击者利用。
本文始发于微信公众号(飓风网络安全):在Windows Servers部署服务中查找漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论