一 、概述
网上已经有触发漏洞的POC和本地提权EXP,还有几篇从不同角度对漏洞进行阐述的文章(包括但不限于以下几篇),但是阅读后对内存的构造和利用过程并不理解,因此自己尝试从新调试走一遍,主要记录调试过程及其他文章中未能读懂的部分,基本原理,提权原理及协议结构等不再重复:
二、配置调试环境
需要配置双虚拟机windbg preview调试,配置内核调试(目标主机):管理员权限启动powershell或cmd,执行如下命令:
bcdedit /set dbgtransportkdnet.dll
bcdedit /dbgsettings NETHOSTIP:调试机IP PORT:50000
bcdedit /debug on
调试机上的windbg设置:
加载符号表及:
sympath SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols
.reload重新加载符号表
Lml 查看加载了哪些符号表
Bp srv2!Srv2DecompressData+0xe0,此时找不到函数定义,需要.reload符号表
!sym noisy打开加载符号过程分析
.reload /f srv2.sys
windbg ERROR_INTERNET_CANNOT_CONNECT 是需要科学上网
发现错误,在system32下面寻找srv2.sys,但实际上该文件在system32/drivers,拷贝后再次加载:
三、调试BOSD
造成漏洞的代码位于:
Srv2.sys的Srv2DecompressData :
前面2个变量相加的时候没做检查造成溢出分配一个较小的内存导致使用该内存时出现问题。
调试时使用ZecOps公开的BOSD poc,打开mem文件后,查看函数调用情况:
查看内存错误情况:
查看出错的内存,非法使用一块未调试
对SrvNetAllocateBuffer附近下断点:
Add ecx,eax执行之前ecx=0xffffff,
执行后,ecx溢出为0x239
搜一下发现win64传参有好几种不同的说法,同过IDA查看函数的参数:
再对比调试器中的参数:确认函数的传参顺序为ecx,edx,r8,r9.
四、LPE过程调试
依然使用ZecOps公开的 poc,但是为了方便观察内存数据变化,做了如下修改:
分析如下关键点:
多次调试分析结合其他文章的讲解后得出申请用于解压缩数据的内存结构如下:
内存的申请过程也有点绕,调试后发现如下顺序:
最终使用nt!ExAllocatePoolWithTag申请了一块0x1278大小的内存,地址开始值可以抽象为0x0000:
但是SrvNetAllocateBuffer成功后的返回值为0x0000+0x1150=0x1150(0xffffd888c577c150-0xffffd888c577b000=0x1150):
,同时在0x1150的0x18出存放了0x0000+0x50(内存可以开始使用的地址)的地址
申请的内存从0x0050可以开始使用,前面部分用于放未压缩的数据,后面存放压缩的数据。未压缩数据大小来自smb数据包header中的offset(0x18)参数,那么SmbCompressionDecompress函数将压缩的数据解压到0x0050+offset(0x18)开始,如果大小能覆盖到0x1168那么就可以改写内存首地址,0x1168-0x0050-0x18=0x1100,看下poc代码:
其中len(what)=0x18,因此写入的数据长度为0x1100。
在SmbCompressionDecompress调用前下断点,第4个参数为解压后存放数据的内容地址,0x0068(0x0000+0x50+offset(0x18)):
同时记录0x1168地址处的内容:
SmbCompressionDecompress调用完毕后,0x68处内容为poc想写入的0x41:
同时0x1168处地址也被改写为token地址(0xFfffc7093924e0a0):
SmbCompressionDecompress完毕后只是处理了压缩的数据部分,未压缩的部分接下来用Memcpy函数拷贝到内存块的首部,长度为offset(0x18),但是此时0x1168存放的内存块首部地址已经被改为token地址(0xFfffc7093924e0a0),对应rcx。
因此实现了对token的改写,提权成功。
*本文作者:kczwa1,转载请注明来自FreeBuf.COM
来源:freebuf.com 2020-05-28 09:00:38 by: kczwa1
请登录后发表评论
注册