从零开始的cve分析- cve-2016-0095 简易记录

时间:2023-03-10 06:36:45
从零开始的cve分析- cve-2016-0095 简易记录

0x00 前言

看k0shl大佬的SSCTF pwn450 Windows Kernel Exploitation Writeup一文,试着写一个x64下的poc。

poc地址:https://github.com/4M4Z4/cve-2016-0095-x64

0x01 环境

  • windows 7 旗舰版 Service Pack 1 64位

0x02 poc

emmm,k0shl大佬的分析文章非常好,我看了都不知道该写些啥了。那就写写我是怎么来确定那个是_SURBOJ结构体的 hDEV 为 0 的。

首先运行蓝屏poc:(将我提供的代码main函数中的NullPageAlloc函数注释掉即可)

  • windbg断下,并显示如下信息:

    从零开始的cve分析- cve-2016-0095 简易记录

  • 查看发生错误的位置的汇编代码,可以发现是test byte ptr [rsi+38h],1这句汇编指令出错,下面查看一下运行这条指令时的寄存器的值

    从零开始的cve分析- cve-2016-0095 简易记录

  • 查看寄存器的值,使用.cxr命令即可

    从零开始的cve分析- cve-2016-0095 简易记录

    可以发现rsi为0,从而导致0地址的引用,触发内存访问错误。那么正常流程下,那个rsi+38h到底指向的是一个什么东西呢?k0shl大佬的分析文章中已经详细给出了。下面是我分析出这个东西是啥的过程,和k0shl的思路类似,但是我并没有调试,而是纯静态分析的。

  • 我们需要知道这个rsi到底是个啥:

    就是这个:[[rdx+50h]+30h] rdx是bGetRealizedBursh的第二个参数

    看了看这个rsi的取值来自bGetRealizedBursh函数的第二个参数。

    从零开始的cve分析- cve-2016-0095 简易记录

    查看栈回溯如下:

    从零开始的cve分析- cve-2016-0095 简易记录

  • 而bGetRealizedBrush的第二个参数来自pvGetEngRbrush(struct _BRUSHOBJ *a1)的第一个参数。

  • 而pvGetEngRbrush的第一个参数来自于EngBitBlt的倒数第3个参数,参数类型依然是_BRUSHOBJ,还是没什么信息,那么继续往上。

  • 而EngBitBlt的倒数第3个参数来自于EngPaint的第三个参数,类型依然还是_BRUSHOBJ,继续往上

  • 继续网上却发现EngPaint的第三个参数来自一个局部变量:

从零开始的cve分析- cve-2016-0095 简易记录

那么继续看看,哪儿改了这个v55,映入眼帘的就是上面那个EBURSHOBJ::vInitBrush函数,跟进去一看,就发现门路了。(其实那个v55是a1,我为了看起清楚,就改了名字,改为了v55)

从零开始的cve分析- cve-2016-0095 简易记录

  • 等于说[rdx+50]就是v21,而v21+24是一个_SURFOBJ结构体(32位的win32k.sys中的符号可以显示,但是64位不显示,不知道为啥...)。我们需要的是[[rdx+50h]+30h]的值,而[rdx+50h]+18h指向的是一个SURFOBJ,而SURFOBJ是公开的:

    typedef struct _SURFOBJ {
    DHSURF dhsurf; //v11+18h
    HSURF hsurf; //v11+20h
    DHPDEV dhpdev; //v11+28h
    HDEV hdev; //v11+30h 指向就是这个
    SIZEL sizlBitmap;
    ULONG cjBits;
    PVOID pvBits;
    PVOID pvScan0;
    LONG lDelta;
    ULONG iUniq;
    ULONG iBitmapFormat;
    USHORT iType;
    USHORT fjBitmap;
    } SURFOBJ;

    所以可知应该是hdev取为了0

0x3 总结

发现替换token是有几率蓝屏的。然后不知道该怎么解决,知道原因是因为Token值会被释放和DeReference。但是不知道怎么来解决。

发现其实好多提权exp都不太稳定额...那不是检测提权exp检测蓝屏 就可以了? emmm,倒是一种思路。