Sei sulla pagina 1di 4

How to Defeat Windows 8 ASLR in Getting the Address of KPCR by cawan (cawan[at]ieee.

org) on 29/10/2012 In Windows XP or earlier version, KPCR is always located at 0xffdff000. It is very important for kernel shellcode in getting system process token in order to duplicate it into another eprocess object which has lower privilege. This action is normally known as token stealing, and it is very useful for privilege escalation. However, starting from Windows 7, it has been ASLRed, and so in Windows 8. This has increased the difficulty in creating kernel shellcode. However, it is not impossible to defeat it. First of all, let see how it is ASLRed in Windows 8. kd> !pcr KPCR for Processor 0 at 81214000: Major 1 Minor 1 NtTib.ExceptionList: 8089612c NtTib.StackBase: 00000000 NtTib.StackLimit: 00000000 NtTib.SubSystemTib: 80879000 NtTib.Version: 005ab660 NtTib.UserPointer: 00000001 NtTib.SelfTib: 00000000 SelfPcr: Prcb: Irql: IRR: IDR: InterruptMode: IDT: GDT: TSS: 81214000 81214120 0000001f 00000000 00000000 00000000 8087c400 8087c000 80879000

CurrentThread: 812230c0 NextThread: 00000000 IdleThread: 812230c0 DpcQueue: Well, the KPCR is at 0x81214000. This address is valid until next reboot. Let see which address range of this KPCR located to. kd> ln 81214000 (81214000) nt!KiInitialPCR Exact matches: nt!KiInitialPCR =

(81218280)

nt!BcpCursor

It is within nt kernel with internal symbol KiInitialPCR. Of course the KiInitialPCR will not be existed in the list of Export Table of nt PE header. So, how to get the address? Method 1, by using the fixed offset of KPCR to a well-known symbol which is included in the Export Table of nt PE header, let's say HalDispatchTable. kd> dd nt!HalDispatchTable l1 811def28 00000004 So, HalDispatchTable is at 0x811def28. Let's check the offset to KPCR. kd> ? 81214000-811def28 Evaluate expression: 217304 = 000350d8

Well, it is 0x00350d8. So, when we need to exploit a device driver, we can calculate the address of KPCR in user mode first before creating the kernel shellcode to be run for privelege escalation. To calculate the KPCR, use the following steps, 1. Use NtQuerySystemInformation() with SystemInformationClass of SystemModuleInformation to get nt kernel base 2. Use LoadLibrary() to load nt kernel image file into user space and get its base (nt kernel base in user space) 3. Use GetProcAddress() to get the address of HalDispatchTable in user space (HalDispatchTable in user space) 4. (HalDispatchTable in kernel base) = (nt kernel base) + (HalDispatchTable in user space) - (nt kernel base in user space) 5. KPCR = (HalDispatchTable in kernel base) + 0x350d8 Well, the 0x350d8 is valid for Windows 8 system. Let's verify by rebooting the machine. kd> dd nt!HalDispatchTable l1 81039f28 00000004 The HalDispatchTable is at 0x81039f28. So by adding 0x350d8 to 0x81039f28 it suppose to be KPCR. kd> ? 81039f28+350d8 Evaluate expression: -2130251776 = 8106f000 The KPCR should be located at 0x8106f000 now. Let's check. kd> !pcr KPCR for Processor 0 at 8106f000: Major 1 Minor 1 NtTib.ExceptionList: 8051612c NtTib.StackBase: 00000000 NtTib.StackLimit: 00000000 NtTib.SubSystemTib: 804f9000 NtTib.Version: 0001604a NtTib.UserPointer: 00000001 NtTib.SelfTib: 00000000 SelfPcr: Prcb: Irql: IRR: IDR: InterruptMode: IDT: GDT: TSS: 8106f000 8106f120 0000001f 00000000 00000000 00000000 804fc400 804fc000 804f9000

CurrentThread: 8107e0c0 NextThread: 00000000 IdleThread: 8107e0c0 DpcQueue: Bingo! We win. For your info, in Windows 7, it is 0x92c. I believe it is service pack dependent, so, if you have chance to verify it in different Windows version, please let me know. Now, let's go to method 2, to defeat ASLR with FS register. In user mode, FS:[0] is always pointing to the current thread object; but in

kernel mode, it is always pointing to KPCR. Let's check. kd> r fs fs=00000030 In all current windows system FS always be 0x30. It is easy to get the base address of this FS value in windbg. kd> dg 30 P Sel Base Limit Type l ---- -------- -------- ---------- 0030 8106f000 00004280 Data RW Ac 0 Si ze -Bg Gr an -By Pr es -P Lo ng Flags -- -------Nl 00000493

Since we don't reboot the mechine yet, the KPCR is still at 0x8106f000. The question now is can we do what dg command did manually? The answer is yes. Let's go for it. First, lets deconstruct the FS value. 15...3|2 index |TI 0..110|0 |1 0 |RPL |0 0

RPL=0 means kernel mode TI=0 means using GDT index=110 means selector index 6 of descriptors Now, get the GDT address by using windbg. Of course in creating kernel shellcode, sgdt instruction should be used. kd> r gdtr gdtr=804fc000 The GDT is at 0x804fc000. Let's dump its memory. kd> dd 804fc000 804fc000 00000000 804fc010 0000ffff 804fc020 0000ffff 804fc030 f0004280 804fc040 0400ffff 804fc050 90000068 804fc060 00000000 804fc070 c00003ff

00000000 00cf9300 00cff300 81409306 0000f200 81008903 00000000 8000924f

0000ffff 0000ffff 900020ab 00000fff 00000000 90680068 00000000 00000000

00cf9b00 00cffb00 80008b4f 0040f300 00000000 81008903 00000000 00000000

Each descriptor is 8 bytes, so, descriptor at index 6 is at 0x804fc030 kd> db 804fc030 l8 804fc030 80 42 00 f0 06 93 40 81 Let's refer the format of descriptor 63...56 |55|54|53|52|51...48 |47|46 |45|44...40|39...16 |15...0 Base 31-24|G |D |R |U |Limit 19-16|P |DPL|S |TYPE |Segment Base 23-0|Segment Limit 15-0 R reserved (0) DPL 0 means kernel, 3 means user G 1 means 4K granularity (Always set in Linux) D 1 means default operand size 32bits U programmer definable P 1 means present in physical memory S 0 means system segment, 1 means normal code or data segment. Type There are many possibilities. Interpreted differently for system and normal descriptors.

So, the base address can be reconstructed as shown below. LSB | 80 42 00 f0 06 93 40 81 | MSB MSB | 81 40 93 06 f0 00 42 80 | LSB 63...56 = 81 39...16 = 06 f0 00 Well, the base address is at 0x8106f000 and it is exactly the KPCR address that we obtained by using "dg 30" command in windbg. In next paper, I will discuss about how to build a platform in creating and testing kernel shellcode in windbg.

Potrebbero piacerti anche