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: 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 Initial: 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: System_process_enumerate: 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 CMD_process_enumerate: 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 CMD_process_found: Mov [rcx+80h], rax // moving the SYSTEM token in rax to CMD token 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.