实验环境

双虚拟机调试

这里我把漏洞机和调试机都放在了虚拟机里,采用虚拟机调试虚拟机的好处就是可以实时保存快照,有空的时候在接着工作(其实是为了更好的加班,开个玩笑~~

1.漏洞机的设置

在虚拟机里安装后系统后,必须进行断网设置 ,因为我在测试调试的时候,运行poc几次后都是成功的,而后就不行了,排除了原因很久,IDA发现,它自动打了补丁(以前内核调试的时候,都没有遇到这种问题)。断网设置如下:

右键漏洞机-->虚拟机设置,这里首先把“打印机 ”给删除了(调试机也一样), 然后点击添加--> "串行端口",并根据截图填写下列信息就好:

进入漏洞机,以管理员打开cmd,分别输入下列命令:

这里写了个自动的WKD.bat脚本,管理员运行它即可:

(原图查看地址:https://imgchr.com/i/uVCxX9)

2. 调试机的设置

调试机的虚拟机设置

在调试机里安装后windbg,设置调试符号,计算机--> 属性 --> 高级系统设置 --> 环境变量

管理员打开windbg,并进行下列nel ebug --> COM

注意:

1. win7的com端口是默认安装的,在系统安装到虚拟机的时候,自己可以查看设备管理器验证一下,都是COM1的。
2. 首先必须删除掉打印机,再进行串口的添加,这样才能保证漏洞机和调试机两边串口名的一致性,两边才能正常通信,不然windbg是附加不上的。比如在虚拟机设置--硬件--设备栏里,漏洞机的串口名为"串行端口2", 而调试机的串口名为"串行端口1",两者就不能通信。在都删除了打印机的情况下,漏洞机和调试机的串口名应该都为"串行端口",这样才能通信。

现在漏洞机和调试机都设置好了,管理员打开windbg,然后在重新打开漏洞机,选择MyDebug; 等待一段时间,windbg出现如图所示,即表示双机调试环境搭建成功。

漏洞原因

原因是在win32k.sys组件中,SetImeInfoEx函数没有对指针进行安全验证; 当指针指向零地址后,在接下的代码又对该区域进行访问,就会引发访问违规,触发蓝屏。所以该漏洞属于空指针引用漏洞。而 SetImelnfoEx 函数只有NtUserSetImeInfoEx调用它,我们就从 NtUserSetImeInfoEx函数开始分析起吧。

在win32k.sys中, NtUserSetImeInfoEx函数是用于将用户进程定义的输入法扩展信息对象设置到与当前进程关联的窗口站中。从上图可以看到NtUserSetImeInfoEx函数只有一个参数a1,而a1参数的类型其实是一个tagIMEINFOEX结构体,这个结构就是输入法的扩展信息结构。值得注意的是NtUserSetImeInfoEx函数里有调用了GetProcessWindowStation来获取当前进程所在窗口站的句柄。而与GetProcessWindowStation函数相对应的函数是在用户层使用CreateWindowStationW创建了一个窗口站,并通过SetProcessWindowStation将窗口站与当前进程相关联。而CreateWindowStationW返回的是一个tagWINDOWSTATION 句柄。

下面我们就先弄明白tagWINDOWSTATION是什么,现在根据github上的代码改写一下poc。

vs2013-->文件-->新建--项目-->Visual C++ -->Win32项目-->控制台应用程序-->空项目。新建好工程后,这里就要设置一下属性了。

编译运行后,得到crash.exe并把它赋值到漏洞机里,然后点击运行crash.exe; 调试机里windbg断下, 并切换到crash.exe进程。

可以看到没有执行CreateWindowStationW函数时,tagWINDOWSTATION->spklList时是有值的。

执行CreateWindowStationW函数后,tagWINDOWSTATION->spklList默认为空值了。

这个SetProcessWindowStation函数,如果大家有兴趣可以逆向一下,因为在我们的重点不是在这里。

那什么是tagWINDOWSTATION呢?窗口站是和当前进程和会话(session)相关联的一个内核对象,tagWINDOWSTATION 包含了剪贴板(clipboard)、原子表、一个或多个桌面(desktop)对象等。

而且这个 NtSetUserImeInfoEx 函数的参数 tagIMEINFOEX a1 是我们可以构造的,是可控的。到这里我们反汇编NtUserSetImeInfoEx函数,并在 94410030 地址处下个断点。

然后g一下,kb看下堆栈的情况,可以看到通过系统调用进入内核;

单步步过win32k!_GetProcessWindowStation;证明该函数返回的是窗口站句柄的内核地址。

到目前为止,我们知道了如下图所示,现在我们单步进入win32k!SetImeInfoEx漏洞函数分析一下:

在比较处发生异常访问。

(原图查看地址:https://imgchr.com/i/uVAOsg)
(原图查看地址:https://imgchr.com/i/uVVlhq)

其实SetImeInfoE就做下面这两个步骤而已,只不过在第一步骤就发生了零页内存访问异常了而已

由上可知,tagWINDOWSTATION窗口站对象的spklList成员,是关联的键盘布局tagKL(KeyBoad Latout)对象链表的头指针, SetImeInfoE函数会遍历spklList链表,直到节点对象pklNext成员回到头指针对象为止。其中判断每个被遍历的节点对象的hkl成员是否与piiex->hkl相等。如果相等会退出循环,否则继续循环遍历。接下来判断键盘布局对象的piiex成员是否为空,且成员变量的fLoadFlag值是否等于零,如果是, 则会把用户自定义的tagIMEINFOEX数据(可由我们自定义构造的)拷贝到键盘布局对象的piiex成员中。

总结—— 用户进程调用CreateWindowStation创建窗口站时, 窗口站对象splList成员会初始值为0,在调用系统服务 NtUserSetImeInfoEx 设置输入法扩展信息的时候,内核函数 SetImeInfoEx 将会访问splList指向位于用户进程地址空间中的零页内存;如果当前进程零页未被映射,函数的操作将引发缺页异常,导致系统 BSOD 的发生。到此漏洞原因分析完毕。

漏洞利用

首先,解决零页地址访问异常的问题,在未开启零页保护的系统下,我们可以通过 NtAllocateVirtualMemory申请0地址内存,来使得零页内存也是可访问的,并构造位于零页中的伪造tagKL键盘布局对象,使得tagKL->hkl也是可控的 (即在[0+14h]处存放我们构造的tagKL->hkl值)。

(原图查看地址:https://imgchr.com/i/uVVcuD)

其次,tagIMEINFOEX结构体是我们可控的,因为NtUserSetImeInfoEx(tagIMEINFOEX a1)函数的a1参数也是我们可以构造的。

现在我们需要shellcode有ring0的权限去执行,那么我们可以修改一个具有ring0权限的函数指针为shellcode指针即可实现ring0权限执行shellcode。内核函数选择hal!HaliQuerySystemInformation函数,因为有一个调用它的ring3函数(NtQueryIntervalProfile函数)是一个未文档化的函数,也就是一个不常用的函数; 这样我们覆盖它的函数指针后对于整个程序执行造成的影响会小一些,相对来说安全些。而且NtQueryIntervalProfile函数是在ntdll.dll中导出的未公开的系统调用,可以直接在Ring3调用 。也就是Ring3调用NtQueryIntervalProfile,其内部会调用内核态nt!HalDispatchTable+0x4处的函数,而我们把nt!HalDispatchTable+0x4的地址,替换为我们的shellcode地址,就可以达到shellcode在内核态上正常执行并提取利用了。

Bitmap GDI 技术

那么我们如何把用户态shellcode的地址替换掉内核态nt!HalDispatchTable+0x4的地址呢?Bitmap GDI 技术可以实现用户态对内核态任意地址读/写(即通过CreateBitmap/GetBitmapBits/SetBitmaps这3个函数实现).

1.把gWorker.pvScan0的地址构造到tagIMEINFOEX结构体上,然后通过漏洞把gManger.pvScan0地址里存储的值替换为gWorker.pvScan0地址
2.gManger利用SetBitmapBits将gWorker.pScan0地址里存储的值设置为HalDisptchTable+4地址
3.gWorker利用GetBitmapBits获取HalDispatchTable+4地址里存储的值(也就是hal!HaliQuerySystemInformation), 存储到&pOrg里去(保存一份hal!HaliQuerySystemInformation,为后面恢复还原做准备)
4.gWorker利用SetBitmapBits将HalDispatchTable+4所指内存的值替换为shellcode的地址
5.调用NtQuerySystemInformation执行shellcode
6.gWorker利用SetBitmapBits将HalDispatchTable+4所指内存的值还原为&pOrg存放的值(即第3步骤设置的值)

1.把gManger.pvScan0的值改gWorker.pvScan0的地址

调试github上的exp,在 HANDLE gManger = CreateBitmap(0x60, 1, 1, 32, bbuf); 处下断点

下面是exp通过构造tagKL和tagIMEINFOEX来把gManger.pvScan0的值改为gWorker.pvScan0的地址。

(原图查看地址:https://imgchr.com/i/uVk81O)

下面是零页内存上的值

下面是完整的tagIMEINFOEX构造的逆向过程

(原图查看地址:https://imgchr.com/i/uVSse0)

现在我们跟入NtUserSetImeInfoEx函数,看它是如何把gManger.pvScan0的值改为gWorker.pvScan0的地址的。

(原图查看地址:https://imgchr.com/i/uVZZP1)

继续跟入NtUserSetImeInfoEx漏洞函数

(原图查看地址:https://imgchr.com/i/uVZWsU)

执行 qmemcpy 后

(原图查看地址:https://imgchr.com/i/uVZxdH)

由上可知, 我们已经把gManger.pvScan0的值改为gWorker.pvScan0的地址,上面的图您可能看着有点奇怪,其实也不用纠结,它只不过是布局tagIMEINFOEX结构体,然后通过SetImeInfoEx漏洞函数,来实现把gManger.pvScan0的值改为gWorker.pvScan0的地址而已。至于为什么赋值给mpv-4(fdb2c75c), 而不是直接赋值给mpv(fdb2c760),是由 _SURFOBJ 结构体的特性决定的。

2. SURFOBJ 结构体

surfobj结构体在《windows Graphics Programming Win32 GDI and DirectDraw》由 Feng Yuan著是有一点讲解的,中文本叫《Windows 图形编程》 2002年出版。

mpv-4 其实就是SURFOBJ->pvBits ,mpv为SURFOBJ->pvScan0;在底层它会将 pvBits 的值更新到 pvScan0

那么这个SURFOBJ结构体是在哪里呢?当我们调用CreateBitmap函数来创建一个bitmap时,SURFOBJ结构就会被附加到进程PEB的GdiSharedHandleTable成员中。GdiSharedHandleTable是一个GDICELL结构体数组的指针(感兴趣的可以调试一下gdi32!CreateBitmap函数,这里我就不逆给你们看了)

(原图查看地址:https://imgchr.com/i/uVeYTJ)

gdicell地址的计算公式为:

(原图查看地址:https://imgchr.com/i/uVeB6K)

通过资料和计算,我们知道gdicell->pKernelAddress刚好指向BASEOBJECT结构,在32位机中,BASEOBJECT+0x10的偏移就是SURFOBJ结构,SURFOBJ结构的pvScan0成员也就是漏洞利用的关键,pvScan0让我们能把用户态的shellcode地址,暂时存放到内核态,提供了一个很狭小的4字节的内核空间,让我们在诸多系统保护机制下,有了可乘之机。

3. gManger利用SetBitmapBits将gWorker.pScan0地址里存储的值设置为HalDisptchTable+4地址

到现在为止,总算完成了第一步骤,现在我们继续往下走,进入第二步骤。

逆向一下 SetBitmapBits((HBITMAP)gManger, sizeof(PVOID), &oaddr); 函数

NtGdiSetBitmapBits把我们的参数继续往下传

(原图查看地址:https://imgchr.com/i/uVnXLT)

跟入GreSetBitmapBits函数,先判断一下size是否为空值,然后通过SURFREF::SURFREF函数获取pkernelAddress的地址。

可以看到 SetBitmapBits 调用 bDoGetSetBitmapBits 时,a3的值默认为零;GetBitmapBits调用时,a3为1.

跟入bDoGetSetBitmapBits ,memcpy把gWorker.pScan0里的值替换为 nt!HalDispatchTable+0x4 的地址。

(原图查看地址:https://imgchr.com/i/uVueTe)
(原图查看地址:https://imgchr.com/i/uVK9HS)

到目前为止, 我们通过SetBitmapBits->NtGdiSetBitmapBits->GreSetBitmapBits->bDoGetSetBitmapBits->memcpy的连续调用,完整了第二部分的数据交换。

4. 通过GetBitmapBits把HalDispatchTable+4地址里存储的值,保存一份到&pOrg里去

我们直接来到GetBitmapBits->NtGdiGetBitmapBits->GreGetBitmapBits下的bDoGetSetBitmapBits

(图片查看地址:https://imgchr.com/i/uVQQp9)

最后进行数据替换,如下图

(原图查看地址:https://imgchr.com/i/uVQ3Ox)

5. 通过SetBitmapBits将HalDispatchTable+4所指内存的值替换为shellcode的地址

拷贝后的值:

6. 调用NtQuerySystemInformation执行shellcode

通过NtQueryIntervalProfile调用nt!HalDispatchTable+0x4,也就是被我们用shellcode地址替换掉的hal!HaliQuerySystemInformation地址。我们可以在nt!KeQueryIntervalProfile+0x23下个断点

这里的shellcode思路很简单就是把系统的Token替换掉我们当前进程的Token,那么当前进程就具备了管理员的权限,从而达到提权的目的。

7. 恢复HalDisptchTable+4的地址处的值

通过 SetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &pOrg); 把shellcode替换回hal!HaliQuerySystemInformation.

到这里所有的调试和利用就完成了,最后看下效果

心得

windows内核漏洞利用,如果内核函数不明白的,就是逆向它的逻辑,你会更加比别人理解这种利用方式;比如CreateBitmap这个函数,对于其他漏洞来说,就需要用到它来做池风水布局,而网上的公式您单看是看不明白的(如果您是追求原理本质,那就只能上手逆了,不然分析漏洞时,疑惑是很多的)。

本人的分析水平是有限的,只能尽量做到这样,所以文中很多错误的地方是有待指正和修改的。

最后,来点小菜鸡的心声(me), 想要飞的高,就请忘记地平线。全剧终...

原创文章申明:

本文为“苏州极光无限信息技术有限公司”原创,未经许可,禁止转载!

windbg分析dmp蓝屏文件_手把手教你分析漏洞 : CVE-2018-8120相关推荐

  1. mysql排插问题_手把手教你分析 MySQL 死锁问题

    原标题:手把手教你分析 MySQL 死锁问题 前言 前几天跟一位朋友分析了一个死锁问题,所以有了这篇图文详细的博文,哈哈~ 发生死锁了,如何排查和解决呢?本文将跟你一起探讨这个问题 准备好数据环境 模 ...

  2. 用WinDbg分析电脑蓝屏文件

    有时Windows 系统经常意外的蓝屏,一个很好的蓝屏故障解决办法和大家一起分享. 首先在讲解之前先做几个名词解释,以便大家理解本文(windows XP为例): 第一步:打开"小内存转储& ...

  3. appium文件夹下无.bin文件_手把手教你Win10应用商店文件夹无权限访问怎么处理

    点击上方蓝字可以订阅哦 微软公司推出windows10系统之后,就希望可以像谷歌一样拥有自己的应用市场,这是为了统一将windows系统应用到所有设备做的铺垫.该应用市场称为windows应用商店,英 ...

  4. linux wait函数头文件_手把手教Linux驱动9-等待队列waitq

    在上一篇<手把手教Linux驱动8-Linux IO模型>我们已经了解了阻塞.非阻塞.同步和异步等相关概念,本文主要讲解如何通过等待队列实现对进程的阻塞. 应用场景: 当进程要获取某些资源 ...

  5. cmd 将文件夹下文件剪切到另外一个文件_手把手教你运行第一个 Java 程序,看不懂你来骂我!...

    码字不易,对你有帮助 **点赞 /转发↪️/关注 ** 支持一下作者 微信搜公众号:不会编程的程序圆br/>看更多干货,获取第一时间更新 在运行第一个 java 程序之前,你需要先将 java ...

  6. arduino温湿度计库文件_手把手教你DIY最便宜的 arduino 温湿度计,详细图文视频教程...

    原标题:手把手教你DIY最便宜的 arduino 温湿度计,详细图文视频教程 冬天人们经常关注家里的温湿度,南方没有暖气更关注温度,北方因为天气干燥,有暖气,所以更关注湿度.下边介绍一个非常简单,并且 ...

  7. macbook没有权限打开文件_手把手教你删除没有权限的文件

    为什么我们没有权限? 在生活中,经常用电脑的朋友们一定遇到过这样的情况,删除一个文件时,遇到需要管理员授权才能查看或者删除的文件,这让人十分的苦恼,这不是要证明我就是我吗? 怎样获得权限? 首先,我们 ...

  8. 揪出“凶手”——实战WinDbg分析电脑蓝屏原因

    http://www.appinn.com/blue-screen-search-code/ 蓝屏代码查询器 – 找出蓝屏的元凶 11 文章标签: windows / 系统 / 蓝屏. 蓝屏代码查询器 ...

  9. 软件_手把手教vscode配置c++,python开发环境

    原创:软件_手把手教vscode配置c++,python开发环境 之前主用Python作为项目开发语言,将项目迁移到arm边缘盒子上后发现arm的cpu不给力,软件速度低于预期,所以计划将部分程序改为 ...

最新文章

  1. Oracle系统结构之修改oracle内存参数
  2. linux 文件属性文件权限
  3. 图像和流媒体 -- 详解YUV数据格式
  4. 我为什么喜欢用C#来做并发编程
  5. 任意两点间的最短路问题(Floyd-Warshall算法)
  6. ES6 generator
  7. 计算机文化基础课程总结,计算机文化基础课程总结.docx
  8. 超时空机战服务器配置信息错误,超时空机战熔炉篇FAQ教你如何合理的使用熔炉...
  9. 02 前端篇(选择器和属性)
  10. group by 按什么区别_失业补助金和失业保险金有什么区别,按什么标准领?不知道亏大了...
  11. A.I. Wiki 人工智能
  12. U890采购入库单修改供应商
  13. JAVA 事务回滚方法调用非事务回滚方法
  14. 36. 有效的数独(技巧)
  15. . java.lang.IllegalArgumentException: requirement failed: Can only call getServletHandlers on a runn
  16. 潘通色卡tcx电子版_潘通色卡电子版Pantone TPX(三)
  17. 数字藏品交易平台开发 数字藏品交易网站开发
  18. 小红书账号分析丨小红书kol速成干货分享
  19. 嫁人就嫁程序猿:不说话则已,开口就是段子手
  20. 国家电网计算机专业考试科目,2019国家电网考试科目:你的专业都考什么?

热门文章

  1. Go使用mgo增删改查聚合操作
  2. Git如何修改文件夹看不清的蓝色显示
  3. 有赞的交易系统架构困局以及破局之道
  4. 华为p50预计售价鸿蒙是什么,华为P50pro预计售价多少 华为P50Pro参数配置
  5. php xml expat,PHP 使用 XML Expat 解释xml文件
  6. 查看mongodb数据路径_Mac OS 中安装和使用 MongoDB 的方法
  7. linux lib lib64 区别,lib,lib32,lib64,libx32和libexec之间的区别
  8. springBoot后台发送内容至邮箱
  9. 高斯噪声调频matlab,基于MATLAB的2ASK调制与解调设计
  10. copy所有的java文件到硬盘_将d:\java目录下的所有.java文件复制到d:\jad目录下,并将原来文件的扩展名从.java改为.jad...