千家信息网

BlueKeep 漏洞利用分析

发表于:2024-11-16 作者:千家信息网编辑
千家信息网最后更新 2024年11月16日,作者:SungLin@知道创宇404实验室时间:2019年9月18日原文链接: https://paper.seebug.org/1035/0x00 信道的创建、连接与释放通道的数据包定义在MCS C
千家信息网最后更新 2024年11月16日BlueKeep 漏洞利用分析

作者:SungLin@知道创宇404实验室
时间:2019年9月18日

原文链接: https://paper.seebug.org/1035/

0x00 信道的创建、连接与释放

通道的数据包定义在MCS Connect Inittial PDU with GCC Conference Create Request中,在rdp连接过程如下图所示:

信道创建数据包格式如下:

在MCS Connect Inittial中属于Client Network Data数据段, MS_T120将会在连接一开始的时候通过函数 termdd!_IcaRegisterVcBin创建一个虚拟通道id是0x1f大小为0x18的结构体,之后就调用 termdd!IcaCreateChannel开始创建大小为0x8c的信道结构体之后将会与虚拟通道id是0x1f绑定,也就是这个结构体将会被我们利用

信道的定义字段主要是名字加上配置,配置主要包括了优先级等

在server对MCS Connect Inittial应答包,将会依次给出对应虚拟通道的id值:

在rdp内核中依次注册的值对应应该是0、1、2、3, MS_T120信道将会通过我们发送的用户虚拟id为3的值再一次绑定,首先通过 termdd!_IcaFindVcBind找到了刚开始注册的虚拟通道id是0x1f,如下所示:

但是在 termdd!_IcaBindChannel时,却将我们自定义的id值为3与信道结构体再一次绑定在一起了,此信道结构体就是MS_T120

同时我们自己的用户id将内部绑定的0x1f给覆盖了

我们往信道MS_T120发送数据主动释放其分配的结构体,其传入虚拟通道id值为3通过函数 termdd!IcaFindChannel在channeltable中查找返回对应的信道结构体:

下图为返回的MS_T120信道结构体,其中0xf77b4300为此信道可调用的函数指针数组:

在这个函数指针数组中主要存放了三个函数,其中对应了 termdd!IcaCloseChanneltermdd!IcaReadChanneltermdd!IcaWriteChannel

我们传入释放MS_T120信道的数据如下,字节大小为0x12,主要数据对应了0x02

之后将会进入 nt! IofCompleteRequest函数,通过apc注入后,将会通过 nt! IopCompleteRequestnt!IopAbortRequest进行数据请求的响应,最终在 termdd!IcaDispatch完成我们发送数据的的请求, _BYTE v2就是我们发送的数据,所以我们发送的数据0x02将会最终调用到IcaClose函数进入IcaCloseChannel函数,最后主动释放掉了 MS_T120信道结构体

0x01 通过RDPDR信道进行数据占位

我们先来了解下rdpdr信道,首先rdpdr信道是文件系统虚拟通道扩展,该扩展在名为rdpdr的静态虚拟通道上运行。目的是将访问从服务器重定向到客户端文件系统,其数据头部将会主要是两种标识和PacketId字段组成:

在这里我们刚好利用到了rdpde客户端name响应的数据来进行池内存的占位

在完全建立连接后,将会创建rdpdr信道的结构体

在window7中,在建立完成后接收到server的rdpdr请求后,通过发送客户端name响应数据,将会调用到 termdd! IcaChannelInputInternal中的ExAllocatePoolWithTag分配非分页池内存,并且其长度是我们可以控制的,基本满足了UAF利用的需求:

可是在windowsxp中,直接发送client name request将会导致内存分配失败,直接进入 termdd! _IcaCopyDataToUserBuffer,并且在Tao Yan and Jin Chen[1]一文中也提到了通过发送client name request在触发一定的条件后将会绕过 termdd!_IcaCopyDataToUserBuffer而进入ExAllocatePoolWithTag分配我们想要的非分页内存,而打破条件如下:

我们先来看看最开始信道结构体的创建,我们可以发现从一开始创建信道结构体的时候,将会出现两个标志,而这两个标志是按照地址顺序排列的,而在上面需要打破的条件中,只要channelstruct +0x108的地址存放的是同一个地址,循环就会被break

我们发送一个正常的rdpdr的name request数据包,头部标识是0x7244和0x4e43

经过 termdd!_IcaCopyDataToUserBuffer之后,将会进入 nt!IofCompleteRequest,在响应请求后进入 rdpdr!DrSession::ReadCompletion,此函数处理逻辑如下,其将会遍历一个链表,从链表中取出对应的vftable函数数组

遍历第一次取出第一张函数数组

传入我们发送的数据后,通过函数数组调用 rdpdr!DrSession::RecognizePacket进行读取

判断头部标志是否为(RDPDR_CTYP_CORE)0x7244

接着将会读取函数vftable第二个地址,进行转发

如下图可以看到rdpdr的数据包处理逻辑

rdpdr经过一系列数据包处理后最终进入了我们关心的地方,将会传入channelstruct通过调用 termdd! _IcaQueueReadChannelRequest进行标志位的处理

最初rdpdr的channelstruct的标志位如下

经过函数 termdd! _IcaQueueReadChannelRequest对此标志的处理后变成如下,所以下一个数据依然会进入 termdd!_IcaCopyDataToUserBuffer,导致我们进行池喷射的失败

回到rdpdr头部处理函数 rdpdr!DrSession::RecognizePacket,我们发现在链表遍历失败后将会进行跳转,最后将会进入读取失败处理函数 rdpdr!DrSession::ChannelIoFailed,然后直接return了

我们构造一个头部异常的数据包发送,头部标志我们构造的是0x7240,将会导致 rdpdr!DrSession::RecognizePacket判断失败,之后将会继续遍历链表依次再取出两张函数数组

最后两个函数数组依次调用 rdpdr!DrExchangeManager::RecognizePacketrdpdr!DrDeviceManager::RecognizePacket,都会判断错误的头部标志0x7240,最后导致链表遍历完后进行错误跳转,直接绕过了 termdd! _IcaQueueReadChannelRequest对标志位的修改,将会打破循环

最后我们连续构造多个错误的数据包后将会进入 ExAllocatePoolWithTag,分配到我们需要的非分页内存!

0x02 win7 EXP 池喷射简要分析

首先被释放的MS_T120池大小包括是0x170,池的标志是TSic

分析Win7 exp 可以知道数据占位是用的rdpsnd信道,作者没有采用rdpdr信道,应该也和喷射的稳定性有关,rdpsnd喷射是再建立完了rdpdr初始化后开始的,在free掉MS_T120结构体前,发送了1044个数据包去申请0x170大小的池内存,这样做可以说应该是为了防止之后被free掉的内存被其他程序占用了,提高free后内存被我们占用的生存几率

占位被free的实际数据大小为0x128,利用的中转地址是0xfffffa80ec000948

之后开始池喷射,将payload喷射到可以call [rax] == 0xfffffa80ec000948的地方,喷射的payload大小基本是0x400,总共喷射了200mb的数据大小,我们先来看下喷射前带标志TSic总共占用池内存大小是58kib左右

喷射完后带TSic标志池内存大小大约就是201mb,池内存喷射基本是成功的,我的win7是sp1,总共内存大小是1GB,再喷射过程中也没有其他干扰的,所以喷射很顺利

图中可以发现基本已经很稳定的0x400大小的池喷射payload,地址越高0x400大小的内存基本就很稳定了

最后断开连接时候,被free的内存已经被我们喷射的0x128大小的数据给占用了

执行call指令后稳定跳转到了我们的payload,成功执行!

参考链接:
[0] https://github.com/rapid7/metasploit-framework/pull/12283
[1] https://unit42.paloaltonetworks.com/exploitation-of-windows-cve-2019-0708-bluekeep-three-ways-to-write-data-into-the-kernel-with-rdp-pdu/
[2] https://wooyun.js.org/drops/%E7%BE%8A%E5%B9%B4%E5%86%85%E6%A0%B8%E5%A0%86%E9%A3%8E%E6%B0%B4%EF%BC%9A%20%E2%80%9CBig%20Kids%E2%80%99%20Pool%E2%80%9D%E4%B8%AD%E7%9A%84%E5%A0%86%E5%96%B7%E6%8A%80%E6%9C%AF.html

数据 信道 函数 大小 结构 标志 内存 通道 头部 数组 处理 地址 池内 分配 两个 客户 客户端 就是 时候 条件 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 数据库习题集和答案 插值语句怎么写数据库 梦幻西游全新服务器 深圳交友软件开发有用吗 重庆企业网络技术服务进货价 服务器udp通讯是什么意思 魔兽对战平台数据库出错 数学学院软件开发实训选题 河南品质软件开发服务标准 网络安全事件发生中的 平台软件开发外包公司 网络运维是做什么的 网络安全 ponytown无法连接服务器 江苏质量网络技术咨询价格行情 魔兽世界怀旧服猎人服务器 网络安全的句子大全 辽宁专业软件开发服务厂家现货 嘉赢网络技术有限公司 第三方软件开发和嵌入式 关于网络文明网络安全的征文 上海安卓应用软件开发多少钱 腾讯云服务器市场规模 服务器管理器添加php 天津1u机架式服务器报价 我认为网络技术 网络安全知识幼儿园绘画 软件开发本科生与研究生区别 中国的网络安全战略模式选择是 网络安全审计简历自我 建行软件开发中心改革
0