您的位置:首页 > Web前端

How to Defeat Windows 8 ASLR in Getting the Address of KPCR

2014-01-08 21:44 513 查看


How to Defeat Windows 8 ASLR in Getting the Address of KPCR

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: 81214000
Prcb: 81214120
Irql: 0000001f
IRR: 00000000
IDR: 00000000
InterruptMode: 00000000
IDT: 8087c400
GDT: 8087c000
TSS: 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 | (81218280) nt!BcpCursor

Exact matches:

nt!KiInitialPCR =

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: 8106f000

Prcb: 8106f120

Irql: 0000001f

IRR: 00000000

IDR: 00000000

InterruptMode: 00000000

IDT: 804fc400

GDT: 804fc000

TSS: 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 Si Gr Pr Lo

Sel Base Limit Type l ze an es ng Flags

---- -------- -------- ---------- - -- -- -- -- --------

0030 8106f000 00004280 Data RW Ac 0 Bg By P 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 |1 0

index |TI |RPL

0..110|0 |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 00000000 0000ffff 00cf9b00

804fc010 0000ffff 00cf9300 0000ffff 00cffb00

804fc020 0000ffff 00cff300 900020ab 80008b4f

804fc030 f0004280 81409306 00000fff 0040f300

804fc040 0400ffff 0000f200 00000000 00000000

804fc050 90000068 81008903 90680068 81008903

804fc060 00000000 00000000 00000000 00000000

804fc070 c00003ff 8000924f 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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: