CVE-2021-40449

admin 2023年7月12日01:38:03CVE-2021-40449已关闭评论44 views字数 2562阅读8分32秒阅读模式

一、 漏洞信息

CVE-2021-40449 是卡巴斯基实验室于2021年8月下旬至9月上旬在Windows 服务器上捕获到相关恶意样本并进行分析后发现的在野提权0day漏洞。

该漏洞发生在win32kfull!GreResetDCInternal中,通过触发UAF(UseAfter Free) 进行本地提权。

二、 测试环境及漏洞复现

测试环境

POC:https://github.com/KaLendsi/CVE-2021-40449-Exploit

靶机: win10 x64 专业版,14393

漏洞复现

CVE-2021-40449

三、 漏洞成因分析

结合卡巴斯基的报告和微软的补丁,发现该漏洞产生是因为win32kfull!GreResetDCInternal 函数存在缺陷:当在用户模式下执行ReserDC 函数并执行系统调用NtGdiResetDC 及其内部函数GreResetDCInternal,此函数获取指向PDC对象的指针,但在函数内部未检查该对象是否已经被释放,导致可以对一个格式错误的PDC对象以某种方式进行利用实现堆任意内核函数的调用。

下图GreResetDCInternal打补丁前后的对比图,其中左图为打补丁后的函数逻辑流程图,可以清晰的看到更新之后的GreResetDCInternal在首部位置多了一下判断语句。

CVE-2021-40449

IDA中的反汇编可以进一步了解到,新的GreResetDCInternal函数会对dco 对象调用次数进行了一次判定,判断本次DCO对象使用次数是否大于1。当使用次数大于1,则说明该对象已经使用过,以此确定该对象结构是否异常,以此来避免UAF的产生。

CVE-2021-40449

四、 漏洞利用分析

UAF构造

该漏洞利用原理来自卡巴斯基提供的思路如下图所示:

CVE-2021-40449

首先调用CreateDCA创建一个DC对象然后通过调用ResetDC去重置DC对象,最后在GreResetDCInternal中触发漏洞。

CVE-2021-40449

GreResetDCInternal执行期间调用hdcOpenDCW去创建新的PDC(旧的在后续过程会被清除),hdcOpenDCW会调用ClientPrinterThunk,而此函数会返回用户模式:

CVE-2021-40449

CVE-2021-40449

在用户模式中,hook mxdwdrv.dll的导出函数DrvEnableDriver

CVE-2021-40449

在hook_DrvEnableDriver中,在传入相同hdc的前提下对ResetDC进行二次调用

CVE-2021-40449

下图为GreResetDCInternal的部分实现过程,在成功调用hdcOpenDCW申请到新的pdc后,首先会将hdc进行交换(即对hdc指向的pdc进行交换),最后调用DeleteDCInternal(传入新的hdc)去销毁旧的pdc,以完成dc置换。

CVE-2021-40449

但是由于hdcOpenDCW_1的执行过程被hook,在hdcOpenDCW_1返回之前进程第二次调用GreResetDCInternal_2(俄罗斯套娃),但是此次GreResetDCInternal_2会正常的执行,通过hdcOpenDCW_2生成一个新的pdc_2并会成功的将旧的pdc_2释放,最后执行完毕。此时,第一次调用hdcOpenDCW_1才算成功结束,并且成功申请到新的pdc_1,接着GreResetDCInternal_1会去清理旧的pdc_1。(PS 上述描述过程中除了pdc_1和pdc_2有区别,其他1、2均指的是同一个东西目的是为了更好的理解)如下图所示:

CVE-2021-40449

两次销毁的pdc对象指向的是同一个(地址为ffff9097845f6010的pdc对象),由于GreResetDCInternal_2已经将该pdc销毁,GreResetDCInternal_1在调用hdcOpenDCW完成后会通过旧的pdc过去DrvResetPDEV的地址并调用,但此时旧的pdc对象已经在GreResetDCInternal_2中被销毁。因此可以通过内存喷射技术,去执行对具有受控参数的任意内核函数的调用。

CVE-2021-40449

如图,正常情况下应该去执行win32kfull!UMPDDrvResetPDEV

CVE-2021-40449

但是由于pdc对象在第二次调用ResetDC已经被销毁,此时通过堆喷射技术,申请与pdc大小一致的对象,来获取到被销毁的这块内存。最后在GreResetDCInternal_1中,由于没有对旧的pdc对象进行检查,造成GreResetDCInternal_1+0x1bb处使用了错误对象的数据,实现指针的利用。(rbx此时指向的是通过堆喷射构造由我们自己控制的对象,从而去控制rax(dispatch addr)和rcx(argc)的值)。

CVE-2021-40449

GreResetDCInternal_1中最终会调用RtlSetAllbits去修改token,达到提权目的。

CVE-2021-40449

CVE-2021-40449

Token修改

  1. 通过带有 SystemHandleInformation 参数的 NtQuerySystemInformation() 函数泄露 ring0 中漏洞利用的访问令牌地址。
  2. 通过 EnumDeviceDrivers() 函数泄漏 ntoskrnl.exe 模块的基地址,从而泄漏 ring0 上的RtlSetAllBits() 地址。
  3. 为RtlSetAllBits()构造特制参数BitMapHeader(在大池上创建一个伪造的 BitMap Header),目的是成功达成“任意地址写任意数据”。过程如下:

  4. 通过 NtSetInformationThread()分配精心制作的 BitMapHeader

CVE-2021-40449

  • 通过调用带有 SystemBigPoolInformation 参数的 NtQuerySystemInformation() 函数泄漏大池中的分配地址。

CVE-2021-40449

CVE-2021-40449

  1. 通过hook DrvEnablePDEV() 中再次调用 ResetDC() 来触发 UAF。

CVE-2021-40449

  1. 通过大量调用CreatePalette()喷射相同大小的且由攻击者定义的Palette对象去占用旧的PDC 对象锁释放的堆内存空间。(其中po_dhpdev_offset改为RtlSetAllbits的地址,po_ppfn_INDEX_DrvResetPDEV_offset改为BitMapHeader的地址)

CVE-2021-40449

  1. GreResetDCInternal在0x1bb处错误的解析“pdc”对象,最后去调用RtlSetAllbits将token+0x40_SEP_TOKEN_PRIVILEGES的值去提升权限。

CVE-2021-40449

CVE-2021-40449

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年7月12日01:38:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2021-40449http://cn-sec.com/archives/1868860.html