CVE-2021-40449 NtGdiResetDC UAF
背景
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::EnablePDEV
、PDEVOBJ::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_user
和PDEV_kernel
偏移0x708
处的指针,指向各自的DEVMODE
结构,这里同样会发生一次用户态函数回调,不过该回调不进行考虑,因为此漏洞利用范围内,被利用的主要是该指针。
完成UMPDDrvResetPDEV
回调后,执行win32kbase!HmgSwapLockedHandleContents
,该函数会将PDC_user
和PDC_kernel
首部的HDC
值和PDC
的引用计数值
进行了互换,从而完成devmode
修改的功能。
后面则是将两个PDC
对象的引用计数值分别减1
,并调用win32kbase!bDeleteDCInternal
将HDC_kernel
索引到的PDC
对象偏移0x30
处指针指向的PDEV
对象引用计数值减1
,值变为0
。而又因为之前的HmgSwap
操作,这里的PDC
和PDEV
实际都是用户传入的HDC
原本指向的对象。
根据MSDN所说,“当该计数器降至零,该对象就会被释放”、“一旦句柄计数减为零,对象的名称就会从对象管理器的命名空间中删除”。意味着该对象可以被占用,而hdcOpenDCW
中又存在用户回调,在用户回调中再对相同的HDC
执行一次ResetDC
,那么该HDC
对应PDEV
对象引用值将减为0
,占用该PDEV
对象后结束回调,回到内核。
至于漏洞的触发点,在原本的UMPDDrvResetPDEV
调用处,该调用发生在hdcOpenDCW
之后,调用函数的地址从PDEV_user
中获取,通过占用,可以获取到修改器调用目标为一个内核读写函数。
利用
该UAF漏洞的利用主要为以下几个步骤:
- 使用
NtQuerySystemInformation
获取利用进程Token.Privileges
在内核中的位置; - 泄露出一个可以用于内核写的内核函数,这里比较通用是
nt!RtlSetAllBits
; - 构造一个
Fake_RTL_BITMAP
,作为nt!RtlSetAllBits
函数参数,大多使用ThreadName
的方式进行构造,不过同样也可以手动申请一片用户态内存进行构造; - HOOK用户回调
DrvEnablePDEV
(HookDrvCompletePDEV
虽然可以成功占用,但执行不到漏洞触发点),在Hook函数中对相同HDC
再执行一次ResetDC
,返回后使用构造的Fake Palette
去占用被释放的PDEV
对象,然后结束当前回调; - 漏洞触发,当前进程权限位全部被启用,完成提权。
在Hook函数中完成占用后的内存布局前后对比如下所示:
PDEV对象占用成功后,完成回调,返回GreResetDCInternal
,可以看到成功地调用到nt!RtlSetAllBits
。
nt!RtlSetAllBits
中仅将rcx
作为参数,而漏洞触发处的第一个参数rcx
同样可以通过占用指定。
nt!RtlSetAllBits
中取rcx
地址0x08
偏移处的QWORD
作为写入的目标地址,而rcx
偏移0
处的DWORD
值整除0x40
后作为计数值,每次向目标地址写入rax
寄存器的值,rax
固定为0xffffffffffffffff
。
总结
这次我分析这个漏洞时尝试尽量不看网上公开的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的更多相关文章
- 近年来爆发的CVE漏洞编号
1.Office漏洞 Office漏洞是大部分APT组织最喜爱的漏洞,Office在个人办公电脑使用量大,对针对性目标是最佳的外网入口,效果也是最直接的. CVE编号 漏洞类型 使用组织 CVE-2 ...
- 【OWASP TOP10】2021年常见web安全漏洞TOP10排行
[2021]常见web安全漏洞TOP10排行 应用程序安全风险 攻击者可以通过应用程序中许多的不同的路径方式去危害企业业务.每种路径方法都代表了一种风险,这些风险都值得关注. 什么是 OWASP TO ...
- Python-爬取CVE漏洞库👻
Python-爬取CVE漏洞库 最近吧准备复现一下近几年的漏洞,一个一个的去找太麻烦了.今天做到第几页后面过几天再来可能就不记得了.所以我想这搞个爬虫给他爬下来做个excel表格,那就清楚多了.奈何还 ...
- codevs 2021 中庸之道
2021 中庸之道 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 给定一个长度为N的序列,有Q次询问,每次 ...
- CVE: 2014-6271、CVE: 2014-7169 Bash Specially-crafted Environment Variables Code Injection Vulnerability Analysis
目录 . 漏洞的起因 . 漏洞原理分析 . 漏洞的影响范围 . 漏洞的利用场景 . 漏洞的POC.测试方法 . 漏洞的修复Patch情况 . 如何避免此类漏洞继续出现 1. 漏洞的起因 为了理解这个漏 ...
- 各浏览器抗uaf机制
今年中旬,微软针对旗下ie浏览器中大量出现的uaf漏洞,对ie浏览器的安全机制进行了一个大幅度的升级,其中主要体现为隔离堆及延迟释放两个机制,顿时又将uaf漏洞的利用向上提升了一个大坎, 但是类似的对 ...
- CVE
一.简介 CVE 的英文全称是"Common Vulnerabilities & Exposures"公共漏洞和暴露.CVE就好像是一个字典表,为广泛认同的信息安全漏洞或者 ...
- 小白日记15:kali渗透测试之弱点扫描-漏扫三招、漏洞管理、CVE、CVSS、NVD
发现漏洞 弱点发现方法: 1.基于端口服务扫描结果版本信息,比对其是否为最新版本,若不是则去其 官网查看其补丁列表,然后去逐个尝试,但是此法弊端很大,因为各种端口应用比较多,造成耗时大. 2.搜索已公 ...
- CVE漏洞爬虫java代码依赖-TestNG
TestNG是Java中的一个测试框架,而该CVE漏洞爬虫示例中所涉及到的java代码中, \Crawler\src\com\***\ThreaderRun.java文件在导入import org.t ...
随机推荐
- HBase之MinorCompact全程解析
转自:https://blog.csdn.net/u014297175/article/details/50456147 Compact作用 当MemStore超过阀值的时候,就要flush到HDFS ...
- golang中往脚本传递参数的两种用法os.Args和flag
1. os.Args package main import ( "fmt" "os" ) func main() { // 执行:./demo.exe 127 ...
- 腾讯云轻量服务器通过Docker搭建外网可访问连接的redis5.x集群
总结记录/朱季谦 最近买了一台4核16的腾讯云轻量应用服务器,花了我快四百的大洋,打算搭建一堆docker组件集群,最先开始是通过docker搭建redis集群,计划使用三个端口,分别是7001,70 ...
- Chrome Performance 页面性能分析指南
1.背景 性能优化是前端开发一个非常重要的组成部分,如何更好地进行网络传输,如何优化浏览器渲染过程,来定位项目中存在的问题.Chrome DevTools给我们提供了2种常用方式 Audits和Per ...
- 学习JAVAWEB第十五天
今天跟着视频做一个简单的登录界面用到javabean,servlet,数据库等知识,还没做完,明天接着做.
- java 多线程 start方法 run方法 简单介绍。
一 start开启一个多线程, run 只是一个内部的方法. package com.aaa.threaddemo; /* * start方法的作用? * 在 Java中启动多线程调用的是start方 ...
- uni微信小程序优化,几行代码就能省100kb的主包空间?
不是标题党,我们公司的项目确确实实是省下了100kb的主包空间,而且还是在没有牺牲任何的性能和业务的前提下实现的. 但是100kb是根据项目大小,所以你用这个插件可能省下超过100kb或者更少. 直接 ...
- Java的代理机制
Java的代理机制 使用代理 Proxzy 可以在运行时创建一组给定接口的新类,这种功能只有在编译时无法确定需要实现哪种接口时才需要使用. 1. 使用代理的时机 假如有一个表示接口的 Class 对象 ...
- 最长公共子序列-LIS
题目描述 时间限制:1.0s 内存限制:256.0MB 问题描述 给定一个长为\(n\)的序列,求它的最长上升子序列的长度. 输入格式 输入第一行包含一个整数\(n\). 第二行包含\(n\)个整数\ ...
- vue组件中使用watch响应数据
在vue中,使用watch来响应数据的变化.watch的用法大致有三种.下面代码是watch的一种简单的用法: 普通用法: <template> //视图 <input v-mode ...