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

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.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Jonathan is fighting against DIO's Vampire minions. There are n of them with strengths a1,a2,…,an. Denote (l,r) as the group consisting of the vampires with indices from l to r. Jonathan realizes that the strength of any such group is in its weakest link, that is, the bitwise AND. More formally, the strength level of the group (l,r) is defined as f(l,r)=al&al+1&al+2&…&ar. Here, & denotes the bitwise AND operation. Because Jonathan would like to defeat the vampire minions fast, he will divide the vampires into contiguous groups, such that each vampire is in exactly one group, and the sum of strengths of the groups is minimized. Among all ways to divide the vampires, he would like to find the way with the maximum number of groups. Given the strengths of each of the n vampires, find the maximum number of groups among all possible ways to divide the vampires with the smallest sum of strengths. Input The first line contains a single integer t (1≤t≤104) — the number of test cases. The description of test cases follows. The first line of each test case contains a single integer n (1≤n≤2⋅105) — the number of vampires. The second line of each test case contains n integers a1,a2,…,an (0≤ai≤109) — the individual strength of each vampire. The sum of n over all test cases does not exceed 2⋅105. Output For each test case, output a single integer — the maximum number of groups among all possible ways to divide the vampires with the smallest sum of strengths.c++实现
07-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值