One of my vulnerability research goals is to find and exploit a privilege escalation bug in a real world driver. In preparation to meet this goal I started working with the HackSys Extreme Vulnerable Driver, specifically the 2.0 version on an x64 Windows 7 sp1 system. Being a new comer to kernel exploitation I chose to start working on the simple stack buffer overflow vulnerability provided by the driver. There are many write ups on how to exploit this vulnerability and the official github repo even comes pre-packaged with an exploit for it.
For some reason none of these exploits were working for me! This was very frustrating because I wanted to follow a working example to help learn how to do it. Eventually, I solved the problem on my own, and I’m very curious to know if anyone else encountered it. Because there are so many write ups for this vuln out there I’m not going to do a full analysis, but instead just focus on the area that was giving me trouble. My wish is that this post will help someone in the future.
The vulnerability is in the
memcpy highlighted below, and the issue I was having is with the
pop rdi also highlighted:
memcpyvulnerability we can overwrite the return address on the stack. You can see though, that before the
ret instruction there is a
pop rdi. What gets popped in to
rdi is a pointer to an
IRP which will be required as an argument to
IoCompleteRequest in order to cleanly exit this call to the driver. But, in order to overwrite the return address we also have to overwrite the pointer to this
IRP. None of the exploits/writeups that I’ve seen take this in to account, and thus they were all crashing my VM rather than giving me a system shell.
To see what I’m talking about here’s what the stack looks like if we break on this
pop rdi instruction during a run that does not attempt to exploit the
As you can see there is a pointer on the top of the stack. Now let’s look at the stack exploiting the buffer overflow vulnerability:
You can see that on the top of the stack we have
AAAAAAAA which is from the buffer overflow. The pointer following that is the address of the userland buffer containing shellcode. The shellcode will run, but because
rdi ends up not having the
IRP that it needs the program will die shortly after the shellcode executes.
Once I realized what the problem was the solution was quite simple. It turns out that this
IRP pointer is also in other locations on the stack at a fixed offset from
rsp at the time that the shellcode is triggered. I added a
mov instruction to the beginning of the standard token stealing shellcode and all of sudden it worked: