CVE-2018-8120 Analyze
type
status
date
slug
summary
tags
category
icon
password
为了方便学习,就用Windows7 SP1 x86的进行学习了,网上也有x64的文章 以及exploit
朋友们可以拓展进行学习

描述

当 Win32k 组件无法正确处理内存中的对象时,Windows 中存在特权提升漏洞,也称为“Win32k 特权提升漏洞”。这会影响 Windows Server 2008、Windows 7、Windows Server 2008 R2。此 CVE ID 不同于 CVE-2018-8124、CVE-2018-8164、CVE-2018-8166。
抄的cve网站的
该漏洞存在与win32k模块中的SetImeInfoEx函数,一起来学习一下吧
 

漏洞分析

双机调试 配置环境就不写了,
直接复制system32的win32k.sys文件 拉到ida中进行分析
notion image
我都写到注释里了
 
接着就去看看谁调用了SetImeInfoEx,我们要获取参数对应的结构体啊,来观察各个判断的结构
notion image
NtUserSetImeInfoEx会调用SetImeInfoEx
看参数v2是_GetProcessWindowStation的返回结果,去msdn上看下这个函数
https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-getprocesswindowstation
如果函数成功,则返回值是窗口工作站的句柄。
notion image
在注解里,我们还看见了SetProcessWindowStation函数,所以这里 我们就可以控制GetProcessWindowStation函数返回的值
notion image
所以我们可以调用CreateWindowStation函数,创建一个句柄;再去调用SetProcessWindowStation函数作为参数值
目前的思路流程是这样的
  1. 调用CreateWindowStation,创建一个窗口工作站对象
  1. 调用SetProcessWindowStation,传入step 1 创建的窗口工作站对象
  1. 然后再去手动调用NtUserSetImeInfoEx函数
  1. NtUserSetImeInfoEx函数会调用SetImeInfoEx
 
但是我们可以先不触发漏洞,而是去寻找下SetImeInfoEx对应的结构体;我们知道SetImeInfoEx函数里创建的各种变量都是由第一个参数来获得的,就是由GetProcessWindowStation返回的;所以我们要观察的结构体,网上都说这个结构是tagWINDOWSTATION,但是没有看到是咋得出这个结果的
 
查看函数原形
所以第一个参数就是PWINDOWSTATION结构,而这个是啥呢
所以也就是tagWINDOWSTATION
 
tagWINDOWSTATION的结构
看下v3也就是a1+0x14,spklList 可以看到试着Ptr32类型,指向tagKL结构
 
所以spklList→hkl 不能等于NtUserSetImeInfoEx传入进去的参数
后面获取spklList→piiex 的值 是个地址,得到v4,往这里进行写入值
 
进行调试
我们要先编写一个Poc
直接抄的网上的了,来解释下代码的意思(在注释里)
notion image
 
一开始还是按往常啥的 用bu bp 不行的
 
看下第一个参数
所以我们知道了 v3是0,所以也肯定不会进while循环了
但是这里是有问题的
 
因为eax是0,+14 也就是0x14为地址,这块内存是没有值的;没有被分配的
所以我们想利用,要把0这块起始地址的内存 给分配出来
要在0x14 这个地方,写上 我们想要写入数据的地址
 
接着利用NtAllocateVirtualMemory函数,分配在0地址开始的内存
先看下分配前的
 
分配后的
不等于,所以不跳;就进入了while循环,所以我们要解决的就是 绕过while循环的验证
我们要写入0x14这个地址的值,与我们传入buf的前8个字节 一样的 就可以绕过while循环了
 
notion image
 
notion image
 
这一次就成功绕过了while循环
notion image
大概就是这个意思
 
我们要写入的话,就是往v4里写,v4是(_DWORD *)v3[11]
v3是0地址,11*4=44=0x2c,所以我们要往0x2c这块地址 写入我们 想要写入的地址
 

漏洞利用

所利用的利用原语就是Bitmap GDI
详细可以参考
这里我就简单写下,下面的图 也是偷的网上的
用户态程序使用CreateBitmap创建得到的Bitmap对象的成员结构中,有存在于内核空间中的成员指针变量pvScan0
而pvScan0这个变量可以在用户态,通过调用GetBitmaps以及SetBitmaps函数,对pvScan0指向的内存地址进行读取写入
所以我们通过写漏洞,更改了pvScan0的值;再调用SetBitmaps函数,修改内核里的值了
当程序调用了CreateBitmap函数后,程序的PEB中的GdiSharedHandleTable表便增加了一个索引,存放着Bitmap的对应GDICELL的地址,就是得由这个计算出来的
Bitmap对应GDICELL的地址 = GdiSharedHandleTable + (handle & 0xffff) * (x64:0x18,x86:0x10)
增加的索引的对象
 
这里的pKernelAddress指向SURFACE OBJECT
 
notion image
注意图中的pvScan0是再SURFOBJ结构中间的
 
 
pvScan0中保存的地址指向内核空间之中,在用户态可以通过GetBitmaps和SetBitmaps函数来对pvScan0指向的内核空间中的内容进行读写操作
 
利用思路:
  1. 可以创建两个Bitmap对象,分别是hManager和hWorker
    1. hWorker里的pvScan0叫:wpv,hManager里的pvScan0叫:mpv
  1. 通过漏洞的任意地址读写的功能,将保存wpv的内存地址赋值到mpv中
    1. (mpv的值 就是wpv的地址)
  1. hManager上调用SetBitmapBits就可以修改wpv中保存的数据
    1. (因为上一步hManager的pvScan0也就是wpv的值 被我们修改为wpv的地址了)
  1. 将wpv的数据 修改为保存HalQuerySystemInformation函数地址的地址。
  1. 利用hWorker上调用SetBitmapBits就可以将HalQuerySystemInformation函数地址修改为ShellCode地址。
  1. 再调用NtQueryIntervalProfile
我不知道网上有没有好的流程图,说实话 我脑子不好用 感觉还是乱了点
 
具体细节
分配内存
 
获取pvScan0的函数
0x30:BASEOBJECT占10个字节,后面到pvScan0是0x20个字节
返回的是pvScan0的地址,就是这个地址 对应的内容才是pvScan0
 
获取GdiShareHandleTable的地址 的 函数
 
创建hManager和hWorker
 
notion image
看网上的文章,还要补全结构
wpv的,pvScan0就是ffaa159c
notion image
但是按理来说 后面就剩5个了啊,但是网上的还是补了第六个 04800200
 
mpv的,pvScan0就是fe61ecdc
notion image
 
我们先一个个走走看
更改mpv的数据,为wpv的地址
notion image
 
原有mpv的pvScan0:ffaa8a44
原有wpv的pvScan0:fe8dd91c
 
看下修改后的
mpv:正好变为了wpv的地址
wpv:正好变为了HalQuerySystemInformation的地址
notion image
 
如果我们再调用SetBitmapBits,设置hWorker;那么就可以往HalQuerySystemInformation的地址 写入shellcode的地址了;最后就是简单的调用对应的DispatchTable里的函数了
notion image
 
成功提权
notion image
 

© muxue 2021-2025