美文网首页
0803漏洞利用分析

0803漏洞利用分析

作者: 看雪学院 | 来源:发表于2019-07-10 18:25 被阅读0次

    作者对0803漏洞的利用工具进行改进使其运用在windows server2012系统环境中,已成功。这是对之前的分析做的小结。本文分享了有关该漏洞的触发原理及利用方法。

    简要说明

    cve-2019-0803

    漏洞类型

    UAF

    时限

    2019年4月公布的补丁

    漏洞位置、应用环境

    全覆盖

    测试环境及场景:

    Sever2008r2

    Win7_64

    server2012r2

    2008r2_sp1

    Win7_64_sp1

    分析该漏洞的目的是想改进EXP使其能运用至server2012系统。最后一小节总结了需更修改的地方。

    漏洞原理

    DDE通信时,client向server请求数据后,sever返回数据时,首先会调用用户层函数_clientCopyDDEIn1(usr32.dll中),该函数是将一些数据填充至tagINTDDEINFO结构,然后再调用hmgSetOwner函数(win32k.sys中),该函数会将tagINTDDEINFO中的成员hIndirect(GDI句柄)返回给client。

    因此,利用思路是,先新建一个A进程并创建得到一个对象句柄X,然后修改用户层函数_clientCopyDDEIn1,将tagINTDDEINFO的成员hIndirect修改为X,这样返回给client的对象就是一个外部对象X。

    Client结束后会释放X,然后再用事先构造好的Y占用该内存区域,那么A进程可以用控制X的函数(此处为SetDIBColorTable函数)修改Y。

    UAF漏洞的利用,雷同double-free漏洞(之前分析的cve-2018-8639),这里也运用了简单的fengshui布局。此外,采用了任意地址读写技术,利用了tagWND结构中cbWNDExtra成员、strName成员、成员spwndParent。

    相关技术

    DDE通信

    UAF与double-free

    double-free

    图2

    UAF

    图3

    由以上两图对比可知,UAF就是double-free的前两步,根据之前cve-2018-8639对double-free的原理分析可知,double-free中的对象B要满足:有相关的函数可以更改B对象的内容。

    那么对于UAF中,存在漏洞的对象A需要满足该条件(本漏洞中就是SetDIBColorTable函数)。其实两个漏洞类型的利用原理是一致的。

    UAF漏洞的利用及任意内存地址读写

    对照图3及”漏洞原理”一节,存在漏洞的对象A是DIB(Device-independent bitmap)类型,然后在client释放A后,用B(构造好的HACCEL)占用A,最后用SetDIBColorTable函数(控制DIB对象)更改B的值。

    关于对象B

    1、B的大小与A相同

    2、SetDIBColorTable函数是如何修改A的,从而构造B

    3、如何通过一次修改B,可以实现任意读写内存地址

    问题1:

    通过读代码[2]可知A就是bitmap对象,其大小0x350(win7/server2008),在server2012系统下为0x370。

    另外,构建A的过程并不是简单的createbitmap(大概与漏洞的触发有关,不是很懂),而是通过建一个"#32768"类的窗口,获得设备上下文的句柄hdc,最后通过hdc得到”OBJ_BITMAP”类型的对象的句柄即对象A。(PS:用gdiview等GDI对象查看的小工具无法看到A)。

    对象B选取 accelerator table对象,一个ACCEL结构的数组。通过CreateAcceleratorTable函数新建对象,参数2确定了对象的大小。当为132时,对象大小为0x350,当为138时,对象大小为0x370。

    问题2:

    关于SetDIBColorTable(hdc,i, n, const RGBQUAD *prgbq)函数如何修改对象DIB,则需逆向该函数(参见“相关函数及术语”),同时还要了解_PALETTE64对象。

    该函数是对hdc中的DIB对象(实际就是_PALETTE64对象)的i开始的n个PALETTENTRY结构进行写。对应到内存中具体的对象的操作就是对_PALETTE64对象的apalColors[]数组进行写操作。

    需要说明的是对象的成员pFirstColor就指向该数组,因此构造一个_PALETTE64对象,使其成员pFirstColor不是指向位图对象的数组apalColors[],而是一个我们想更改的内存位置,那么再调用SetDIBColorTable函数时,令i为0,n为1,就更改了我们指定的内存。

    (这一处没想通,需要好好分析下SetDIBColorTable的具体过程)

    根据code,构造的ACELL数组是在第[15]号ACELL放入构造的_PALETTE64对象地址,然后构造的_PALETTE64对象的成员pFirstColor(偏移0x80处)放入待更改的内存地址xxxx。这样调用SetDIBColorTable函数后就能更改xxxx处的值。

    问题3:

    如何通过更改一个值,达到任意读写内存的目的。此处利用了tagWND结构中cbWNDExtra成员、strName成员、成员spwndParent。

    创建两个icon类的窗口分别为hwnd1和hwnd2,然后设置xxxx为hwnd1的成员cbWNDExtra(偏移0xe8)的地址,通过UAF漏洞更改一次cbWNDExtra值,使窗口hwnd1可以越界写hwnd2(用函数SetWindowLong),然后越界写hwnd2的StrName中的buffer。

    hwnd2就可以调用函数SetWindowText实现任意内存地址写。任意内存地址读:先通过越界写更改hwnd2的成员spwndParent,然后hwnd2通过调用GetAncestor函数实现任意内存地址读。

    fengshui布局

    为了使A释放后,B能顺利占据其内存区域,对内核池进行布局(括号内表示server20012系统下),布局使用的对象为ACCEL。

    1、因为A的大小为0x350(0x370),分配200个由132(138)个ACCEL组成的0x350(0x370)大小的ACCEL数组,占用内存空间中分散的0x350(0x370)大小的内存空洞。

    2、分配1000个由533(527)个ACCEL组成的0xCB0(0xC90)大小的ACCEL数组,使新分配的内存页面留出0x350(0x370)的空间,方便A能分配至此.(0x350=0x1000-0xc90)。

    3、分配400个bitmap对象。

    4、创建对象A,占用之前构造的内存空洞。

    5、再分配400个bitmap对象。

    6、释放第三步分配的前300个bitmap对象。

    释放A后

    1、释放400个从第300到第700的bitmap。

    2、分配2000个构建好的ACCEL数组,即用B占A释放后留下的内存空间。

    用户层函数截持

    __ClientCopyDDEIn1是用户层函数

    截持过程

    目的:在call _ClientCopyDDEIn1指令后开始截持。

    1、截持跳板

    UCHAR HijackJmpShellcode[] = {

    0x50, //push rax

    0x48, 0xB8, //mov rax, 0xcccccccc

    0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,

    0xFF, 0xE0 //jmp rax

    };//13个字节

    2、跳转后运行的程序

    HijackTrampoFunc PROC

    pushr8

    lea rax,[rsp+50h]

    mov r8,qword ptr g_BitMapAddr

    mov qword ptr [rax+30h],r8

    mov r8,qword ptr [rax+20h]

    mov byte ptr [r8+2],2

    pop r8

    pop rax

    xor r8d,r8d

    mov eax,eax

    lea rcx,[rsp+20h]

    lea edx,[r8+18h]

    jmp qword ptr ContinueAddr

    HijackTrampoFunc ENDP

    红色:关键的替换返回对象的代码

    蓝色:堆栈平衡

    绿色:原函数中被HijackJmpShellcode[](13个字节)覆盖的指令

    黄色:跳转到覆盖后的指令,继续执行,ContinueAddr中存放mov[rsp+98h+var_78], r11,指令的地址

    说明:以上为win7中的__ClientCopyDDEIn1函数,win2012中有细微差别。

    3、跳转

    HijackJmpShellcode[3-10]8个字节放入HijackTrampoFunc程序的地址。

    函数逆向

    截持后运行的红色代码是关键,这块代码的编写首先需要了解__ClientCopyDDEIn1的功能,然后要知道tagINTDDEINFO的结构信息(主要是成员hIndirect的偏移),最后要知道在这个函数中tagINTDDEINFO在内存中的哪个位置,最终才能将其成员hIndirect替换为我们的DIB对象的句柄。

    _ClientCopyDDEIn1的功能

    _ClientCopyDDEIn1(void*p1,structtagINFDDEINFO*p2)

    把p1写入p2,p1是以外层函数__ClientCopyDDEIn1的参数(通过rcx寄存器传入)为内存地址中的值。P2是栈空间中的地址([rsp+40h][rbp-58h]),所以该函数就是复制p1处的数据填充至栈空间(以[rsp+40h]为首地址)。

    tagINTDDEINFO的结构信息

    根据code中的红色代码,猜测偏移40h为成员hIndirect,之后又更改了偏移30处的指针指向的第2字节的值为2(不知道是个啥)。

    说明:好在这一点win server 2008和win server 2012没有不同,不然要到哪去分析tagINTDDEINFO的结构信息!!!!

    token替换[4]

    1、获得当前进程的_EPROCESS结构

    2、通过_EPROCESS结构中的成员ActiveProcessLinks及成员UniqueProcessId(pid)遍历搜索出system进程(pid为4)

    3、保存system进程的token值

    4、覆盖当前进程的token

    图1

    说明:

    1、对于第1步,之前算得了两个icon类窗口的地址即pwndIcon1和pwndIcon2,用其中的pwndIcon1即得到图中的tagWND的地址,通过图中的关系可以得到当前进程的_EPROCESS结构。

    2、图中各结构中成员的偏移值在不同的系统中不相同,在server2008与server2012的具体值可通过windbg获得,在code中有标出。

    3、覆盖token时又卡了。写内存时BOSD,一开始以为server12引进了什么安全机制不允许token替换,后来发现是写操作用的函数SetWindowText中的一些注意事项。参见“相关函数及术语”的“SetWindowText”。

    相关函数及术语

    Bitmap和DIB :https://www.xuebuyuan.com/1492074.html

    SetWindowText

    BOOL SetWindowText(

    HWND hwnd,

    LPCTSTR lpString

    );//hwnd

    窗口的句柄,lpString指向一个空结束的字符串的指针

    具体操作:

    把窗口tagWND结构中的成员StrName中的Buffer成员指向的内存处写入lpString字符串。tagWND结构参考图1:

    应用于提权中的写操作:更改Buffer值(即写地址),调用SetWindowText,对内存中任意地址进行写操作,但在运用中遇到一些问题:

    1、lpString是以空结束的字符串,因此再写内存时,会多覆盖1字节的0,测试时导致BOSD(因为对当前进程的token值后的一字节也进行了修改,修改为0),因此,保存token后的若干字节(这些字节是以0结尾的),然后再覆盖token之后,对这些值再重写一下。

    unsignedlonglong tmp = ReadPtrFromKernelMemory(MyEPROCESSAddr + OFFSET_SECTOKEN_WIN7+8);

    wchar_t tmp2[5] = { 0x00 };

    tmp2[3] = (tmp >> 48) & 0xFFFF;

    tmp2[2] = (tmp >> 32) & 0xFFFF;

    tmp2[1] = (tmp >> 16) & 0xFFFF;

    tmp2[0] = (tmp >> 0) & 0xFFFF;

    ....

    ....

    WriteKernelAddress(MyEPROCESSAddr + OFFSET_SECTOKEN_WIN7 + 8, tmp2);

    2、当lpString字符串长度大于成员StrName的MaximumLength(该值在第一次调用SetWindowText时确定)时,会在Buffer指针指向的内存处写入任意值,最终导致BOSD(因为对当前进程的token值附近进行了修改)。

    因此在第一次调用SetWindowText时(为了之后测试是否能写成功),尽量使StrName的MaximumLength大一些。

    3、tagWND结构在server 2012系统中已经不公开。因此也花了些时间确定其成员StrName,cbwndExtra的偏移量及tagWND结构的长度。

    SetDIBColorTable函数

    UINT SetDIBColorTable(

    HDC hdc,

    UINT iStart,

    UINT cEntries,

    const RGBQUAD *prgbq

    );

    4 个参数

    A. Gdi32.dll

    SetDIBColorTable()->ZwGdiDoPalette()->系统调用号

    图1

    B. User32.dll

    存在ZwGdiDoPalette()

    C. Win32k.sys

    NtGdiDoPalette()->GreSetDIBColorTable()->XEPALOBJ::vCopy_rgbquad

    参数如图1中的ZwGdiDoPalette():

    因此调用GreSetDIBColorTable()参数值同SetDIBColorTable()。

    Surface_object = *(struct SURFACE **)(HDC_Copy2 + 0x1F8);

    // surface object pointer from HDC+0x1F8[3]

    ....

    v10 = *((_QWORD *)Surface_object + 15);

    Obj_15 = v10;

    //Obj_15就是PALETTE64对象,这里偏移了15

    ....

    XEPALOBJ::vCopy_rgbquad((XEPALOBJ *)&Obj_15, rgb, start, numm);

    //开始覆值

    汇编

    //r10是change_offset即PALETTEENTRY rdx是rgb即RGBQUAD

    //就是对PALETTEENTRY覆值RGBQUAD

    两个对象的结构

    typedef struct tagRGBQUAD {

    BYTE rgbBlue;

    BYTE rgbGreen;

    BYTE rgbRed;

    BYTE rgbReserved;

    } RGBQUAD;

    typedef struct tagPALETTEENTRY {

    BYTE peRed;

    BYTE peGreen;

    BYTE peBlue;

    BYTE peFlags;

    } PALETTEENTRY, *PPALETTEENTRY, *LPPALETTEENTRY;

    server2008与server2012

    1、由于_ClientCopyDDEIn1函数在不同系统中实现的细微差异,因此在截持时要做相应的修改,包括HijackTrampoFunc中绿色部分及黄色部分的继续跳转的地址ContinueAddr的值。

    2、Fengshui布局中对象大小的设置。

    3、Token获取时,内核结构在不同系统中,各成员的偏移位置的不同。

    4、任意内存地址读写时,tagWND结构中关键成员偏移位置的确定及tagWND的长度。

    5、内核函数的调用(Nt**)转换为调用用户层函数。因为不同系统中内核函数的调用号不同,代码中(win7场景)对内核函数的调用,用在win2012系统中不能成功,好在都有对应的用户层函数,直接替换就好。

    看雪ID:Sebastianasd

    https://bbs.pediy.com/user-816842.htm

    本文由看雪论坛 Sebastianasd 原创

    转载请注明来自看雪社区

    京华结交尽奇士,意气相期矜豪纵。今夏与君相约看雪,把酒言欢,共话安全技术江湖梦。

    10大议题正式公布!第三届看雪安全开发者峰会重磅来袭!

    相关文章

      网友评论

          本文标题:0803漏洞利用分析

          本文链接:https://www.haomeiwen.com/subject/yolkkctx.html