HEVD 学习笔记
1. HEVD 概述 + 环境搭建
HEVD作为一个优秀的内核漏洞靶场受到大家的喜欢,这里选择x86的驱动来进行黑盒测试学习内核漏洞,作为学习笔记记录下来
从以下的 github 可以下载 Release 版本的驱动文件,下载之后就是安装了
1.1 安装驱动
-
HEVD和专项利用工具以调试字符串的形式打印大量的信息。我们既可以从调试方主机(使用WinDbg调试器),也从被调试方主机(使用DebugView工具)查看这些信息。
在调试方输入:ed nt!Kd_Default_Mask 8 启动打印调试字符串的功能,然后输入 g
在虚拟机中使用管理员身份运行 dbgView 程序,并勾选以下选项:
-
将预构建的程序包(驱动+漏洞)下载到被调试方(即被攻击主机),选择有漏洞的 x86 驱动
-
使用加载驱动的软件安装该驱动,我这里使用 KMD:以管理员身份运行该程序,点击即可安装并启动服务
-
启动服务成功后,DebugView 和 Windbg 都打印出如下的字符串即为安装成功
-
验证HEVD模块是否已加载,其符号是否已成功映射
输入 lm m H* 可以看到 HEVD 模块已被成功加载
输入 x /D HEVD!a* 发现该符号文件并未被加载:
为了加载该符号文件,需要弄清楚该符号文件应该存放的路径,输入 !sym noisy,此时再输入 x /D HEVD!a*
从上面的调试信息可以看出,该符号文件在我的电脑中的所在路径为:e:\mysymbol\HEVD.pdb\8921ACC09C6B46A38CA2F42DA3E21ADA1\HEVD.pdb
在我的电脑上创造该路径,并将 HEVD.pdb 文件复制到这个文件夹下:
输入 .reload 重新加载一下,再输入 x /D HEVD!a*,即可看到列出的函数,说明此时的符号文件已经被加载
1.2 驱动信息
按以下调试信息输入命令查看驱动信息:
3: kd> lm m HEVD
Browse full module list
start end module name
ae46f000 ae4b9000 HEVD (private pdb symbols) e:\mysymbol\HEVD.pdb\8921ACC09C6B46A38CA2F42DA3E21ADA1\HEVD.pdb
3: kd> !drvobj HEVD 2
Driver object (86eb6b98) is for:
\Driver\HEVD
DriverEntry: ae4b70ea HEVD!GsDriverEntry
DriverStartIo: 00000000
DriverUnload: ae4b3000 HEVD!DriverUnloadHandler
AddDevice: 00000000
Dispatch routines:
[00] IRP_MJ_CREATE ae4b3048 HEVD!IrpCreateCloseHandler
[01] IRP_MJ_CREATE_NAMED_PIPE ae4b35c2 HEVD!IrpNotImplementedHandler
[02] IRP_MJ_CLOSE ae4b3048 HEVD!IrpCreateCloseHandler
[03] IRP_MJ_READ ae4b35c2 HEVD!IrpNotImplementedHandler
[04] IRP_MJ_WRITE ae4b35c2 HEVD!IrpNotImplementedHandler
[05] IRP_MJ_QUERY_INFORMATION ae4b35c2 HEVD!IrpNotImplementedHandler
[06] IRP_MJ_SET_INFORMATION ae4b35c2 HEVD!IrpNotImplementedHandler
[07] IRP_MJ_QUERY_EA ae4b35c2 HEVD!IrpNotImplementedHandler
[08] IRP_MJ_SET_EA ae4b35c2 HEVD!IrpNotImplementedHandler
[09] IRP_MJ_FLUSH_BUFFERS ae4b35c2 HEVD!IrpNotImplementedHandler
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION ae4b35c2 HEVD!IrpNotImplementedHandler
[0b] IRP_MJ_SET_VOLUME_INFORMATION ae4b35c2 HEVD!IrpNotImplementedHandler
[0c] IRP_MJ_DIRECTORY_CONTROL ae4b35c2 HEVD!IrpNotImplementedHandler
[0d] IRP_MJ_FILE_SYSTEM_CONTROL ae4b35c2 HEVD!IrpNotImplementedHandler
[0e] IRP_MJ_DEVICE_CONTROL ae4b3064 HEVD!IrpDeviceIoCtlHandler
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL ae4b35c2 HEVD!IrpNotImplementedHandler
[10] IRP_MJ_SHUTDOWN ae4b35c2 HEVD!IrpNotImplementedHandler
[11] IRP_MJ_LOCK_CONTROL ae4b35c2 HEVD!IrpNotImplementedHandler
[12] IRP_MJ_CLEANUP ae4b35c2 HEVD!IrpNotImplementedHandler
[13] IRP_MJ_CREATE_MAILSLOT ae4b35c2 HEVD!IrpNotImplementedHandler
[14] IRP_MJ_QUERY_SECURITY ae4b35c2 HEVD!IrpNotImplementedHandler
[15] IRP_MJ_SET_SECURITY ae4b35c2 HEVD!IrpNotImplementedHandler
[16] IRP_MJ_POWER ae4b35c2 HEVD!IrpNotImplementedHandler
[17] IRP_MJ_SYSTEM_CONTROL ae4b35c2 HEVD!IrpNotImplementedHandler
[18] IRP_MJ_DEVICE_CHANGE ae4b35c2 HEVD!IrpNotImplementedHandler
[19] IRP_MJ_QUERY_QUOTA ae4b35c2 HEVD!IrpNotImplementedHandler
[1a] IRP_MJ_SET_QUOTA ae4b35c2 HEVD!IrpNotImplementedHandler
[1b] IRP_MJ_PNP ae4b35c2 HEVD!IrpNotImplementedHandler
驱动装载的地址是 0xae46f000,DriverEntry 的地址是 0xae4b70ea,所以 DriverEntry 的偏移地址是 0x480EA,IRP_MJ_DEVICE_CONTROL 的分发函数偏移地址 0x44064
1.3 IDA 分析
-
使用IDA对驱动进行分析,可以看到在DriverEntry首先是创建了设备对象
INIT:00448036 push eax ; DeviceObject INIT:00448037 push edi ; Exclusive INIT:00448038 push FILE_DEVICE_SECURE_OPEN ; DeviceCharacteristics INIT:0044803D push FILE_DEVICE_UNKNOWN ; DeviceType INIT:0044803F lea eax, [ebp+DestinationString] INIT:00448042 push eax ; DeviceName INIT:00448043 push edi ; DeviceExtensionSize INIT:00448044 push ebx ; DriverObject INIT:00448045 call ds:IoCreateDevice
-
随后就是对分发函数的赋值以及符号链接的创建
INIT:00448075 push 1Ch INIT:00448077 pop ecx INIT:00448078 mov eax, offset DispatchCommon INIT:0044807D lea edi, [ebx+DRIVER_OBJECT.MajorFunction] INIT:00448080 rep stosd INIT:00448082 mov eax, offset DispatchCreateAndClose INIT:00448087 mov dword ptr [ebx+70h], offset DispatchIoCtrl INIT:0044808E mov [ebx+38h], eax INIT:00448091 mov [ebx+40h], eax INIT:00448094 mov eax, [ebp+DeviceObject] INIT:00448097 mov [ebx+_DRIVER_OBJECT.DriverUnload], offset DriverUnload INIT:0044809E or [eax+DEVICE_OBJECT.Flags], DO_DIRECT_IO INIT:004480A2 mov eax, [ebp+DeviceObject] INIT:004480A5 and [eax+DEVICE_OBJECT.Flags], 0FFFFFF7Fh INIT:004480AC lea eax, [ebp+DestinationString] INIT:004480AF push eax ; DeviceName INIT:004480B0 lea eax, [ebp+SymbolicLinkName] INIT:004480B3 push eax ; SymbolicLinkName INIT:004480B4 call ds:IoCreateSymbolicLink
-
根据IDA识别的结果就可以得知符号名,根据符号名就可以完成和驱动的连接与通信
INIT:00448134 aDeviceHacksyse: ; DATA XREF: DriverEntry(x,x)+14↑o INIT:00448134 text "UTF-16LE", '\Device\HackSysExtremeVulnerableDriver',0 INIT:00448182 ; const WCHAR aDosdevicesHack_0 INIT:00448182 aDosdevicesHack_0: ; DATA XREF: DriverEntry(x,x)+25↑o INIT:00448182 text "UTF-16LE", '\DosDevices\HackSysExtremeVulnerableDriver',0
-
在 DispatchIoCtrl 中,程序将 IoControlCode 取出减去 0x222003 以后得到下标,在用这个下标从 Index_Table 中取出函数地址表的下标。在根据这个地址表的下标从 Func_Table 中获得函数地址以后跳转到该函数执行
PAGE:00444064 ; int __stdcall DispatchIoCtrl(int, PIRP Irp) PAGE:00444064 DispatchIoCtrl proc near ; DATA XREF: DriverEntry(x,x)+87↓o PAGE:00444064 PAGE:00444064 Irp = dword ptr 0Ch PAGE:00444064 PAGE:00444064 push ebp PAGE:00444065 mov ebp, esp PAGE:00444067 push ebx PAGE:00444068 push esi PAGE:00444069 push edi PAGE:0044406A mov edi, [ebp+Irp] PAGE:0044406D mov ebx, STATUS_NOT_SUPPORTED PAGE:00444072 mov eax, [edi+60h] ; 取出CurrentStackLocation指针赋给eax PAGE:00444075 test eax, eax PAGE:00444077 jz loc_4444C5 PAGE:0044407D mov ebx, eax PAGE:0044407F mov ecx, [ebx+IO_STACK_LOCATION.Parameters.DeviceIoControl.IoControlCode] PAGE:00444082 lea eax, [ecx-222003h] ; switch 109 cases PAGE:00444088 cmp eax, 6Ch PAGE:0044408B ja loc_4444AD ; jumptable 00444098 default case PAGE:00444091 movzx eax, ds:Index_Table[eax] PAGE:00444098 jmp ds:Func_Table[eax*4] ; switch jump
-
这两张表的内容如下,其中的FuncTable中的每一个地址都代表了不同的漏洞
PAGE:004444E0 Func_Table dd offset loc_44409F, offset loc_4440CF, offset loc_4440F1 PAGE:004444E0 ; DATA XREF: DispatchIoCtrl+34↑r PAGE:004444E0 dd offset loc_444113, offset loc_444135, offset loc_44415A ; jump table for switch statement PAGE:004444E0 dd offset loc_44417F, offset loc_4441A4, offset loc_4441C9 PAGE:004444E0 dd offset loc_4441EE, offset loc_444213, offset loc_444238 PAGE:004444E0 dd offset loc_44425D, offset loc_444282, offset loc_4442A7 PAGE:004444E0 dd offset loc_4442CC, offset loc_4442F1, offset loc_444316 PAGE:004444E0 dd offset loc_44433B, offset loc_444360, offset loc_444385 PAGE:004444E0 dd offset loc_4443AA, offset loc_4443CF, offset loc_4443F4 PAGE:004444E0 dd offset loc_444419, offset loc_44443E, offset loc_444463 PAGE:004444E0 dd offset loc_444488, offset loc_4444AD PAGE:00444554 Index_Table db 0, 1Ch, 1Ch, 1Ch PAGE:00444554 ; DATA XREF: DispatchIoCtrl+2D↑r PAGE:00444554 db 1, 1Ch, 1Ch, 1Ch ; indirect table for switch statement PAGE:00444554 db 2, 1Ch, 1Ch, 1Ch PAGE:00444554 db 3, 1Ch, 1Ch, 1Ch PAGE:00444554 db 4, 1Ch, 1Ch, 1Ch PAGE:00444554 db 5, 1Ch, 1Ch, 1Ch PAGE:00444554 db 6, 1Ch, 1Ch, 1Ch PAGE:00444554 db 7, 1Ch, 1Ch, 1Ch PAGE:00444554 db 8, 1Ch, 1Ch, 1Ch PAGE:00444554 db 9, 1Ch, 1Ch, 1Ch PAGE:00444554 db 0Ah, 1Ch, 1Ch, 1Ch PAGE:00444554 db 0Bh, 1Ch, 1Ch, 1Ch PAGE:00444554 db 0Ch, 1Ch, 1Ch, 1Ch PAGE:00444554 db 0Dh, 1Ch, 1Ch, 1Ch PAGE:00444554 db 0Eh, 1Ch, 1Ch, 1Ch PAGE:00444554 db 0Fh, 1Ch, 1Ch, 1Ch PAGE:00444554 db 10h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 11h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 12h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 13h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 14h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 15h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 16h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 17h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 18h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 19h, 1Ch, 1Ch, 1Ch PAGE:00444554 db 1Ah, 1Ch, 1Ch, 1Ch PAGE:00444554 db 1Bh PAGE:004445C1 align 2
-
如果取出的函数地址表的下标是0x1C,那么对应的就是最后一个跳转地址,也就是loc_4444AD。而这个地址中的代码是在告知用户,发送的IOCTL是不合法的IOCTL
PAGE:004444AD loc_4444AD: ; CODE XREF: DispatchIoCtrl+27↑j PAGE:004444AD ; DispatchIoCtrl+34↑j PAGE:004444AD ; DATA XREF: ... PAGE:004444AD push ecx ; jumptable 00444098 default case PAGE:004444AE push offset aInvalidIoctlCo ; "[-] Invalid IOCTL Code: 0x%X\n" PAGE:004444B3 push 3 ; Level PAGE:004444B5 push DPFLTR_IHVDRIVER_ID ; ComponentId PAGE:004444B7 call ds:DbgPrintEx PAGE:004444BD add esp, 10h PAGE:004444C0 mov ebx, STATUS_INVALID_DEVICE_REQUEST PAGE:004444C5 PAGE:004444C5 loc_4444C5: ; CODE XREF: DispatchIoCtrl+13↑j PAGE:004444C5 ; DispatchIoCtrl+66↑j PAGE:004444C5 and [edi+_IRP.IoStatus.Information], 0 PAGE:004444C9 xor dl, dl ; PriorityBoost PAGE:004444CB mov ecx, edi ; Irp PAGE:004444CD mov [edi+_IRP.IoStatus.anonymous_0.Status], ebx PAGE:004444D0 call ds:IofCompleteRequest PAGE:004444D6 pop edi PAGE:004444D7 pop esi PAGE:004444D8 mov eax, ebx PAGE:004444DA pop ebx PAGE:004444DB pop ebp PAGE:004444DC retn 8 PAGE:004444DC DispatchIoCtrl endp
-
总结:要触发不同的漏洞,IOCTL是从0x222003开始,每次都要增加4,最多可以增加0x1B次
1.4 测试漏洞利用工具
相同的程序包中还包含一组专项利用工具,我们可以通过执行适当的命令来运行其中每一个工具。
-
下载 github 中的 HEVD 项目,使用 VS 2017 打开 C:\Users\soma\Downloads\HackSysExtremeVulnerableDriver-master\HackSysExtremeVulnerableDriver-master\Exploit\HackSysEVDExploit.sln
-
重新生成,得到 HackSysEVDExploit.exe
-
将生成的程序拖入虚拟机,下面我们尝试使用其中一些工具,并将cmd.exe设置为待运行的程序,如下图所示
1)以管理员身份运行 cmd.exe
2)进入以下页面即为启动成功
3)输入 HackSysEVDExploit.exe -c cmd -p 使用Pool Overflow漏洞利用工具,如下图所示:
4)如果整个漏洞利用过程运行成功,目标程序(cmd.exe)将被分配更高的权限。通过执行命令“whoami”可以确认,该程序确实提权运行了,结果如下图所示。