-
-
[翻译]Windows内核驱动攻击(Pt. 2) - 通过栈溢出获取系统权限
-
发表于:
2017-9-10 23:49
7844
-
[翻译]Windows内核驱动攻击(Pt. 2) - 通过栈溢出获取系统权限
这篇文章里,我们将浏览一个简单的HEVD驱动漏洞 - 栈溢出。攻击代码将附在最后。
下一篇文章会介绍介绍shellcode。然后我们会进行更复杂的驱动攻击!
首先,我们把驱动.sys文件加载到IDA里看看它的结构。你将会很庆幸我们的驱动里编译时有符号表选项,这使得逆向简单得多!
在driver最开始被加载时,DriverEntry函数是driver的入口。它做了许多事情,比如说,创建IO设备和设置驱动路径 -
\\Device\\HackSysExtremeVulnerableDriver。这个函数接着设置IRP(I/O 申请数据包)handler(我觉得中文翻译handle,handler太晦涩,具体可以看这个链接)- 这是我们最关心的部分。
函数
IrpDeviceIoCtlHandler 被分配给了 DriverObject MajorFunction 数列的第14个成员。这个函数包含一系列switch选项,这些选项将基于用户在应用程序代码中DeviceIoContrl调用时提供的IOCTL决定那个函数会被运行。
我们关心的函数是
StackOverflowIoctlHandler 的 handler。这个函数会在用户使用IOCTL数为
0x222003
调用DeviceIoControl
时处理用户的请求。
在调用
StackOverflowIoctlHandler 后,调用
TriggerStackOverflow 函数前,会有一些设置。
这其中包含以下代码:
你应该立刻就能发现这里应该有漏洞。因为这里有一个从 userBuffer 到
kernelBuffer (大小为2048 bytes)的 memcpy,并且这个size 大小是交由用户通过
userBufferSz 决定。
所以我们要怎么利用这个漏洞攻击呢?简单。 我们只需要提供比
kernelBuffer (大小为2048 bytes)更多的数据,然后再告诉
memcpy 我们的数据大小(这里我们的数据是多大就写多大)。驱动会
memcpy 我们的数据到驱动内核栈,并且傻傻的帮我们覆盖掉栈上的返回指针。
漏洞找到了,那我们开始真正的攻击吧!
我们设置一个断点来看看攻击是怎么运行的吧。首先我们在WinDbg里运行命令
uf HEVD!TriggerStackOverflow 来得到现在
TriggerStackOverflow 函数在加载后的HEVD模块的地址。这个地址会随着每次开机而变化 - 因为 ASLR(一个通过每次开机时随机化系统library加载地址来防止攻击者使用系统library的机制,很老的一个想法,但会让攻击者稍微麻烦一点).
0: kd> uf HEVD!TriggerStackOverflow
HEVD!TriggerStackOverflow [c:\hacksysextremevulnerabledriver\driver\stackoverflow.c @ 65]:
65 a11a462a 680c080000 push 80Ch
65 a11a462f 68d8211aa1 push offset HEVD!__safe_se_handler_table+0xc8 (a11a21d8)
[...]
92 a11a46be 83c430 add esp,30h
94 a11a46c1 eb21 jmp HEVD!TriggerStackOverflow+0xba (a11a46e4)
HEVD!TriggerStackOverflow+0xba [c:\hacksysextremevulnerabledriver\driver\stackoverflow.c @ 98]:
98 a11a46e4 c745fcfeffffff mov dword ptr [ebp-4],0FFFFFFFEh
100 a11a46eb 8bc7 mov eax,edi
101 a11a46ed e867c9ffff call HEVD!__SEH_epilog4 (a11a1059)
101 a11a46f2 c20800 ret 8
现在我们想做的是找到找到最终ret函数相对于这个函数起始位置的位置。我们之所以要做这一步是因为我们想通过知道函数名字以及相对位置来找到我们想要的ret,这样我们就不用再考虑ASLR了。
0: kd> ? a11a46f2 - HEVD!TriggerStackOverflow
Evaluate expression: 200 = 000000c8
现在我们知道了ret相对于函数起始位置的位置是
0xc8。我们可以设置新断点:
0: kd> bu HEVD!TriggerStackOverflow+c8
现在我们通过输入 g 恢复被攻击虚拟机的运行,然后回到我们的被攻击虚拟机接着写我们的攻击代码!
为了与驱动通信,我们要给他写个handler。我们可以通过使用CreateFile打开物理驱动路径(在DriverEntry 函数中的DestinationString)。和平常一样,先查查看这个函数的文档来看看参数都是用来干嘛的。
接下来我们需要分配一个用于给驱动
memcpy 数据的缓存。我们可以使用
VirtualAlloc。我给了这个缓存一个page。(注意这里给缓存上设置了运行和写权限,因为内核最后会执行这个缓存上的shell code)。(shell code就是些2进制码,每个程序编译到最后都是二进制码,而计算机cpu能运行的其实到最后也就是二进制码。这个文章中的shellcode的用处就是提升当前进程的权限到系统权限)
现在我们先给这个缓存区放满A试试。
RtlFillMemory(uBuffer, PAGE_SIZE, 0x41);
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)