背景

  CVE-2021-40449是一个存在于Win32k内核驱动中的UAF漏洞。该漏洞在2021年八月下旬九月上旬被Kaspersky发现用于野外攻击活动中。通过Hook win32k驱动执行NtGdiResetDC过程中发生的用户模式回调,完成对目标对象的释放和占用,最终实现指定内核函数的调用,以进行内核内存的读写操作,修改利用对象的Token权限,实现EOP。

分析

  此次分析是在Windows 10 1809中进行。

  首先在用户模式调用CreateDC时,会执行至win32k内核调用win32kfull!NtGdiResetDC,再执行至win32kbase!hdcOpenDCW,调用堆栈如下:

......  win32kbase!PDEVOBJ::PDEVOBJ

......  win32kbase!hdcOpenDCW+0x240

......  win32kfull!GreResetDCInternal+0x11a

......  win32kfull!NtGdiResetDC+0xd6

......  nt!KiSystemServiceCopyEnd+0x25

......  win32u!NtGdiResetDC+0x14

......  gdi32full!ResetDCWInternal+0x16b

......  GDI32!ResetDCW+0x31

......  CVE_2021_40449!main

  执行的用户回调主要发生在win32kbase!PDEVOBJ::PDEVOBJ中,该函数应是一个PDEV对象的初始化函数,和win32kfull!NtGdiResetDC传入参数中的HDC有关联。初始化函数中有两个用户回调:PDEVOBJ::EnablePDEVPDEVOBJ::CompletePDEV。这两个用户回调主要是对HDC中的PDEV对象进行操作,PDEV对象通过PDEV::Allocate分配内存。





  执行完初始化函数,回到hdcOpenDCW,继续执行至GreCreateDisplayDC,该函数初始化一个PDC对象,并将上面初始化的PDEV对象的内存地址放到PDC偏移+0x30处。



  然后返回PDC 0偏移处的DC句柄值HDC,该值也作为win32kbase!hdcOpenDCW的返回值,返回值win32kfull!GreResetDCInternal

  hdcOpenDCW返回的HDC传入DCOBJ::DCOBJ,返回hdcOpenDCW初始化的PDC对象的内存地址。



  接着读取PDEV对象0xAB8偏移处的函数指针并执行,注意此处的PDEV并不是在上一步的hdcOpenDCW中初始化的,而是在用户态调用ResetDC前,调用CreateDC生成的。为进行区分,本文中将其称为HDC_user

  GreResetDCInternal的函数参数HDC_user,同样通过DCOBJ::DCOBJ返回PDC_user对象,该对象偏移0x30处为PDEV_user对象的内存地址。

  取PDEV_user偏移0xAB8处函数指针,执行UMPDDrvResetPDEV,传入参数分别为PDEV_userPDEV_kernel偏移0x708处的指针,指向各自的DEVMODE结构,这里同样会发生一次用户态函数回调,不过该回调不进行考虑,因为此漏洞利用范围内,被利用的主要是该指针。



  完成UMPDDrvResetPDEV回调后,执行win32kbase!HmgSwapLockedHandleContents,该函数会将PDC_userPDC_kernel首部的HDC值和PDC引用计数值进行了互换,从而完成devmode修改的功能。



  后面则是将两个PDC对象的引用计数值分别减1,并调用win32kbase!bDeleteDCInternalHDC_kernel索引到的PDC对象偏移0x30处指针指向的PDEV对象引用计数值减1,值变为0。而又因为之前的HmgSwap操作,这里的PDCPDEV实际都是用户传入的HDC原本指向的对象。

  根据MSDN所说,“当该计数器降至零,该对象就会被释放”“一旦句柄计数减为零,对象的名称就会从对象管理器的命名空间中删除”。意味着该对象可以被占用,而hdcOpenDCW中又存在用户回调,在用户回调中再对相同的HDC执行一次ResetDC,那么该HDC对应PDEV对象引用值将减为0,占用该PDEV对象后结束回调,回到内核。

  至于漏洞的触发点,在原本的UMPDDrvResetPDEV调用处,该调用发生在hdcOpenDCW之后,调用函数的地址从PDEV_user中获取,通过占用,可以获取到修改器调用目标为一个内核读写函数。

利用

  该UAF漏洞的利用主要为以下几个步骤:

  1. 使用NtQuerySystemInformation获取利用进程Token.Privileges在内核中的位置;
  2. 泄露出一个可以用于内核写的内核函数,这里比较通用是nt!RtlSetAllBits
  3. 构造一个Fake_RTL_BITMAP,作为nt!RtlSetAllBits函数参数,大多使用ThreadName的方式进行构造,不过同样也可以手动申请一片用户态内存进行构造;
  4. HOOK用户回调DrvEnablePDEV(Hook DrvCompletePDEV虽然可以成功占用,但执行不到漏洞触发点),在Hook函数中对相同HDC再执行一次ResetDC,返回后使用构造的Fake Palette去占用被释放的PDEV对象,然后结束当前回调;
  5. 漏洞触发,当前进程权限位全部被启用,完成提权。

  在Hook函数中完成占用后的内存布局前后对比如下所示:



  PDEV对象占用成功后,完成回调,返回GreResetDCInternal,可以看到成功地调用到nt!RtlSetAllBits



  nt!RtlSetAllBits中仅将rcx作为参数,而漏洞触发处的第一个参数rcx同样可以通过占用指定。

  nt!RtlSetAllBits中取rcx地址0x08偏移处的QWORD作为写入的目标地址,而rcx偏移0处的DWORD值整除0x40后作为计数值,每次向目标地址写入rax寄存器的值,rax固定为0xffffffffffffffff





  POC代码

总结

  这次我分析这个漏洞时尝试尽量不看网上公开的POC,仅根据Kaspersky的文章寻找漏洞位置,结果花了很多时间,遇到挺多问题的。比如寻找漏洞点时,不会出现BSOD,并且!pool不能马上看到对象内存状态变成free,还是去瞄了一些公开的POC,确认自己方向没问题。

  emmm最后好歹自己完成了POC,虽然耗时长且代码拉胯,相比那些优秀的POC通用性低,但是收获也很多,起码漏洞前后附近的代码各个角落都翻了一遍,而且一些坑下次可以避免。

参考

[1] MysterySnail attacks with Windows zero-day

[2] CVE-2021-40449 Exploitation

CVE-2021-40449 NtGdiResetDC UAF的更多相关文章

  1. 近年来爆发的CVE漏洞编号

    1.Office漏洞 Office漏洞是大部分APT组织最喜爱的漏洞,Office在个人办公电脑使用量大,对针对性目标是最佳的外网入口,效果也是最直接的. CVE编号  漏洞类型 使用组织 CVE-2 ...

  2. 【OWASP TOP10】2021年常见web安全漏洞TOP10排行

    [2021]常见web安全漏洞TOP10排行 应用程序安全风险 攻击者可以通过应用程序中许多的不同的路径方式去危害企业业务.每种路径方法都代表了一种风险,这些风险都值得关注. 什么是 OWASP TO ...

  3. Python-爬取CVE漏洞库👻

    Python-爬取CVE漏洞库 最近吧准备复现一下近几年的漏洞,一个一个的去找太麻烦了.今天做到第几页后面过几天再来可能就不记得了.所以我想这搞个爬虫给他爬下来做个excel表格,那就清楚多了.奈何还 ...

  4. codevs 2021 中庸之道

    2021 中庸之道  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description 给定一个长度为N的序列,有Q次询问,每次 ...

  5. CVE: 2014-6271、CVE: 2014-7169 Bash Specially-crafted Environment Variables Code Injection Vulnerability Analysis

    目录 . 漏洞的起因 . 漏洞原理分析 . 漏洞的影响范围 . 漏洞的利用场景 . 漏洞的POC.测试方法 . 漏洞的修复Patch情况 . 如何避免此类漏洞继续出现 1. 漏洞的起因 为了理解这个漏 ...

  6. 各浏览器抗uaf机制

    今年中旬,微软针对旗下ie浏览器中大量出现的uaf漏洞,对ie浏览器的安全机制进行了一个大幅度的升级,其中主要体现为隔离堆及延迟释放两个机制,顿时又将uaf漏洞的利用向上提升了一个大坎, 但是类似的对 ...

  7. CVE

    一.简介 CVE 的英文全称是"Common Vulnerabilities & Exposures"公共漏洞和暴露.CVE就好像是一个字典表,为广泛认同的信息安全漏洞或者 ...

  8. 小白日记15:kali渗透测试之弱点扫描-漏扫三招、漏洞管理、CVE、CVSS、NVD

    发现漏洞 弱点发现方法: 1.基于端口服务扫描结果版本信息,比对其是否为最新版本,若不是则去其 官网查看其补丁列表,然后去逐个尝试,但是此法弊端很大,因为各种端口应用比较多,造成耗时大. 2.搜索已公 ...

  9. CVE漏洞爬虫java代码依赖-TestNG

    TestNG是Java中的一个测试框架,而该CVE漏洞爬虫示例中所涉及到的java代码中, \Crawler\src\com\***\ThreaderRun.java文件在导入import org.t ...

随机推荐

  1. HttpRunner3的变量是如何传递的

    HttpRunner3的变量可以在测试类的用例配置中通过variables添加,也可以在测试步骤中使用extract().with_jmespath()提取出来放到变量x,再用$x传递给下一个接口使用 ...

  2. 【刷题-LeetCode】229. Majority Element II

    Majority Element II Given an integer array of size n, find all elements that appear more than ⌊ n/3 ...

  3. T-SQL的存储过程

    1.简介 存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时 ...

  4. MyCms 自媒体 CMS 系统 v2.6,SEO 优化升级

    MyCms 是一款基于Laravel开发的开源免费的自媒体博客CMS系统,助力开发者知识技能变现. MyCms 基于Apache2.0开源协议发布,免费且不限制商业使用,欢迎持续关注我们. V2.6 ...

  5. C++初始化列表各情况分析

    今天回顾了下C++初始化列表的知识,接下来我对这一知识作一总结. 我们在定义了一个类的时候,需要对类的成员进行初始化.关于初始化,有两种方法,一种在初始化列表中进行,另一种就是在构造函数中进行,对于这 ...

  6. 获取URL中的某段字符

    1. Location 对象 Location 对象包含有关当前 URL 的信息. Location 对象是 window 对象的一部分,可通过 window.Location 属性对其进行访问. ️ ...

  7. JavaScript之详述闭包导致的内存泄露

    一.内存泄露 1. 定义:一块被分配的内存既不能使用,也不能回收.从而影响性能,甚至导致程序崩溃. 2. 起因:JavaScript的垃圾自动回收机制会按一定的策略找出那些不再继续使用的变量,释放其占 ...

  8. nginx多ip多端口多域名方式

    目录 一:Nginx虚拟主机 1.基于ip的方式 2.基于多端口的方式 3.基于多域名的方式 一:Nginx虚拟主机 基于多IP的方式 基于多端口的方式 基于多域名的方式 1.基于ip的方式 [roo ...

  9. SP19149 INS14H - Virus Revisited

    可以发现,如果一个整体一起考虑是不能找到一个合适的状态来描述这个情形的. 因此可以考虑寻找整体的反面,也就是将每个维度分开考虑. 不难发现每个维度本质上是一样的,因此不需要考虑不同维度之间的区别. 那 ...

  10. 将string字符串中的换行符进行替换

    /** * 方法名称:replaceBlank * 方法描述: 将string字符串中的换行符进行替换为"" * */ public static String replaceBl ...