CVE-2021-1732

admin 2023年7月12日01:40:56CVE-2021-1732已关闭评论51 views字数 3630阅读12分6秒阅读模式

一、 漏洞信息

CVE-2021-1732是蔓灵花(BITTER)APT组织在某次攻击行动中使用的0Day漏洞。该漏洞利用Windows操作系统win32k内核模块一处用户态回调机会,破坏函数正常执行流程,造成窗口对象扩展数据的属性设置错误,最终导致内核空间的内存越界读写。当受影响版本的Windows操作系统用户执行攻击者构造的利用样本时,将会触发该漏洞,造成本地权限提升。

二、 测试环境及漏洞复现

测试环境

POC:https://github.com/Pai-Po/CVE-2021-1732/tree/main/CVE-2021-1732

靶机: win10 x64 专业版,1909

漏洞复现

CVE-2021-1732

三、 漏洞成因分析

win32kfull!xxxCreateWindowEx在进行窗口创建时,当其窗口对象tagWND的cbwndExtra字段不为0时,它将调用win32kfull!xxxClientAllocWindowClassExtraBytes触发回调,该回调将返回R3的User32!_xxxClientAllocWindowClassExtraBytes函数,然后在R3通过系统堆分配器(RtlAllocateHeap)为WndExtra申请内存。

攻击者hook此回调函数后,在自定义回调函数中,可以调用NtUserConsoleControl 并传入当前窗口的句柄,这将改变内核结构成员(指向 WndExtra 区域)的属性,并设置相应的标志以指示该成员现在是一个offset。之后,攻击者可以在回调中调用 NtCallbackReturn 并返回任意值。当回调结束返回内核模式时,返回值会覆盖之前的offset,但不会清除相应的标志。之后,内核代码直接使用未经检查的偏移值进行堆内存寻址。

正常的调用流程如下:

CVE-2021-1732

而发生漏洞利用后的流程会有所变化,主要表现在_xxxClientAllocWindowClassExtraBytes的调用过程,_xxxClientAllocWindowClassExtraBytes被hook后去执行自定义的MyxxxClientAllocWindowClassExtraBytes,去执行NetuserConsoleControl和NtCallbackReturn如下图所示:

CVE-2021-1732

CVE-2021-1732

通过上图可以知道:当窗口的扩展数据大小tagWND.cbWndExtra不为0时,win32kfull!xxxCreateWindowEx 内部通过内核回调机制调用用户态user32!_xxxClientAllocWindowClassExtraBytes函数,在用户空间申请窗口对象扩展数据所需内存,最终将指针返回给窗口对象的tagWND.pExtraBytes。

CVE-2021-1732

下面介绍内核窗口对象tagWND的扩展数据有两种保存方式:

1) 保存于用户态系统堆:即上图所示的正常流程,用户态系统堆申请的扩展数据内存指针直接保存于tagWND.pExtraBytes。

  1. 保存于内核态桌面堆:函数NtUserConsoleControl调用会通过DesktopAlloc在内核态桌面堆分配内存,计算分配的扩展数据内存地址到桌面堆起始地址的偏移,保存在tagWND.pExtraBytes中,并修改tagWND.extraFlag |=
    0x800,如下图所示:

CVE-2021-1732

tagWND对象的部分成员已列出,如下图所示:

CVE-2021-1732

综上所述,该漏洞的实质就是,在创建一个带扩展内存的窗口时,内核中xxxClientAllocWindowClassExtraBytes的应用层回调对来自应用层返回的数据校验不严导致,通过hook xxxClientAllocWindowClassExtraBytes,并在hook函数中调用NtUserConsoleControl/NtCallbackReturn可以将目标窗口的poi(tagWND+0x28)+0x128位置设置为任意offset,从而导致越界写入。

具体做法是先创建一个正常的Wnd1对象,并保存其offset,然在创建Wnd2(漏洞)的过程中通过hook
xxxClientAllocWindowClassExtraBytes为Wnd2设置一个自定义offset,具体方法是令 Wnd2.pExtraBytes
== Wnd1.poi(tagWnd+0x28)+0x8的值

即Wnd1的kernel_desktop_heap_base。 另外在Wnd2创建过程中,为了能够找到Wnd内核对象的地址会使用内存喷射技术(大量申请在释放),最后通过匹配cbWndExtra字段进行查找。

四、 漏洞利用分析

核心:构造任意地址的读写权限。

过程(在构造exp过程中,会用到三个tagWnd对象Wnd0、Wnd1、Wnd2其中Wnd2是带有漏洞的)。

CVE-2021-1732

PS:下面介绍过过程中涉及到的tagWndk,tagbody指的是同一个字段即poi(tagWnd+0x28)。

  1. 首先利用漏洞将Wnd2的pExtraBytes中的offset修改为Wnd0的offset。

CVE-2021-1732

  1. 将Wnd0的pExtraBytes改为offset寻址方式。

CVE-2021-1732

  1. 利用漏洞能力修改Wnd2.pExtraBytes为Wnd0的offset (tagWND0的offset 由tagWND0+0x8获得),调用SetWindowLong修改tagWND0.cbWndExtra
    = 0x0fffffff,从而使Wnd0. pExtraBytes获得越界写入能力。

CVE-2021-1732

CVE-2021-1732

在xxxSetWindowLong函数中,会判断index+4\<=cbWndExtra。

CVE-2021-1732

若符合则通过Wnd2调用SetWindowLong,将pwnd+0xc8的位置设置为0x0fffffff,由于Wnd2内核对象的pwnd. pExtraBytes已经被设置为Wnd0内核对象的pwnd内核偏移,此时将直接把0x0fffffff写入到Wnd0内核对象的pwnd+0xc8处,即是修改Wnd0内核对象的pwnd. cbwndExtra,如下图所示逻辑,其中if中对应扩展内存的offse寻址方式,else为内存寻址方式。

CVE-2021-1732

Windbg中调试后可知,v32通过offset寻址计算出来的地址为Wnd0的cbwndExtra字段,此时大小为20,紧接着dwNewLong会将cbwndExtra大小修改为0xfffffff。

CVE-2021-1732

最后,由于Wnd0的cbwndExtra被设置的非常大因此可以通过xxxSetWindowLongptr对其相邻的Wnd内核对象进行越界写入。

PS:offset寻址结果 = pExtraBytes(offset)+ index + kernel_desktop_heap_base

CVE-2021-1732

  1. 通过Wnd0调用SetWindowLongPtr去设置Wnd1的dwstely字段,并通过Wnd1调用SetWindowLongPtr将spmenu设置为fakespmenu伪造的menu对象,配合GetMenuBarInfo函数实现任意地址读。

CVE-2021-1732

首先,通过Wnd0调用SetWindowLongPtr去修改Wnd1的dwStely属性。其中dwpWnd0_to_pWnd1_kernel_heap_offset + g_dwExStyle_offset(828)为Wnd 0- Wnd 1内核对象的pwnd内核偏移的差值+0x18(0x18为dwStely的偏移)。

CVE-2021-1732

接着通过Wnd1调用SetWindowLongPtr将spmenu设置为fakespmenu伪造的menu对象。

CVE-2021-1732

可以看到SetWindowLongPtr的第二参数(nIndex)被设置为GWLP_ID,微软定义为-12。

CVE-2021-1732

在xxxSetWindowLongPtr中当nIndex小于0时,会调用xxxSetWindowData去处理,在xxxSetWindowData当nIndex=-12时,会使用dwNewLong将poi(tag+0x28)+0x98处的数据替换,也就是将Wnd1中的spmenu替换为我们自定义的fakespmenu,另外也会将旧的spmenu返回。

CVE-2021-1732

GetMenuBarInfo函数的部分实现如下图所示,当其第二参数、第三参数分别设置成-3,1的时候可以通过mbi对指定地址的前16个字节进行读取。

CVE-2021-1732

读取过程如下所示:

CVE-2021-1732

  1. 获得任意地址读写权限后,需要泄漏一个桌面堆上的内核对象地址来定位EPROCESS,这里步骤4中为tagWND1设置伪造spMenu时SetWindowLongPtr返回值就是原spMenu的内核地址,如下图所示spMenu+0x100为当前进程的EPROCESS。

CVE-2021-1732

获取当前进程的 EPROCESS 地址后,遍历 EPROCESS->ActiveProcessLinks 链表,找到 PID等于 4 的进程(System 进程),将其Token 复制到当前进程,即可完成提权。

CVE-2021-1732

CVE-2021-1732

  1. 将Token替换之后,还需要将之前修改的字段进行恢复,防止蓝屏。

CVE-2021-1732

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