viernes, 29 de diciembre de 2017

Linux Kernel Debugging with VMWare Player Free

Intro

This post should be a short one in the sense that, it will only cover how to configure two Linux virtual machines, one the debug host and another one the debugee, under a Windows host.
The reason to do this post was encouraged due to not finding the right information (maybe my fault) to look at on my journey to analyse CVE-2017-1000112, and had to figure it out.

As a final note, this post means I am shifting a bit my research towards the Linux Kernel instead of desperately trying to find an exploitable user land heap vulnerability since, to easily exploit a vulnerability on the heap you either need:
  • No ASLR
  • A scripting environment
    • This happens mostly in browsers since we have JavaScript and the likes
  • Be so lucky that your heap corruption happens on a function pointer
    • and also have all the ROP Gadgets at hand
  • Be Chris Evans and be able to craft scriptless exploits

Credit where credit is due

This post is a "diversion" from the post Adapting the POC for CVE-2017-1000112 to Other Kernels. It is a good post in the sense that, it holds you by the hand and guides you through to set up the right version of the Kernel with the right code sources. This can be sometimes tedious to do so, mad props for doing it NeverEndingSecurity!

(useless) .vmx file

If you have done a bit of research before landing on this blog post, you might have already encountered the following options:
debugStub.listen.guest64 = "TRUE"
debugStub.listen.guest64.remote = "TRUE"
Such options are the ones that, regarding some sources on the interwebz or the VMWare OSDev Wiki, will enable you to debug your kernel over a network connection. This wasn't working for me at all, no matter which combinations of these would I add. Wild guess here: These options don't work on the Free Player Version.
But hey! do not worry if you still have no clue what I am talking about, you don't need these to debug your Kernel if you're reading this post :)

kgdb

This was another bit of a rabbit hole. It was caused due to trying to establish a connection through either TCP or UDP protocols for remote debugging.
At first, one would land (or I did land first) on the following resource: https://www.kernel.org/pub/linux/kernel/people/jwessel/kgdb/
Said resource is a bit scarce on documentation and it takes for granted you're a sysadmin of level 42 and not just someone with enough curiosity to debug a Kernel exploit.

kgdboe

"The term kgdboe is meant to stand for kgdb over ethernet. To use kgdboe, the ethernet driver must have implemented the NETPOLL API, and the kernel must be compiled with NETPOLL support. Also kgdboe uses unicast udp. This means your debug host needs to be on the same lan as the target system you wish to debug."
Ok so, kgdboe seems what I wanted. Now I needed to know if I had it enabled on the Kernels that I just installed. This can be done by checking on the modules folder:
ls -l /sys/modules/ | grep -i "kgdb"

It seems that I didn't have the kgdboe module loaded. For the sake of simplicity I am skipping the part on which I failed to compile the whole kernel with kgdboe and NETPOLL support.

kgdboc

I skipped it because something caught my attention. It was the presence of the kgdboc module:
The kgdboc driver was originally an abbreviation meant to stand for "kgdb over console". Kgdboc is designed to work with a single serial port. It was meant to cover the circumstance where you wanted to use a serial console as your primary console as well as using it to perform kernel debugging. Of course you can also use kgdboc without assigning a console to the same port.
That seems what I actually wanted to do: having a remote terminal debugging another host. No need for networking! Just some old school serial ports!

Serial ports on VMWare Player Free

Let's do it! Open VMWare Player and, on the settings of the debugging machine (the one that is going to connect to the remote debugger), we need to add a new device. A Serial Port just like in the following image:


There are some key points here on the right of the image. Since this is our debugging machine:
  • The name of the pipe should be the same for both machines
  • This is the debugger connecting to a remote target: This end is the client.
  • Of course, the other end is a Virtual Machine (VMWare will do its magic)
  • We are debugging, we need some kind of "sync" by consuming CPU: Polling

With this in mind, we can configure the debugged machine where our debugging server will be:


The only thing that is different on this configuration is the This end is the server setting.
We can now test our newly connected serial port:


Configuring kgdboc

One of the final steps we need to make is to tell kgdb which serial port to send and receive its debugging information from. There are two ways to configure this, on boot time (add the option on grub to our init line), or the one we are going to cover, which is writing to the module file on runtime. Remember the kgdboe section?
echo ttyS1,115200 > /sys/module/kgdboc/parameters/kgdboc
The really final step is to trigger a debugging interrupt to let the client attach to the remote debugger.

SysReq keys

The SysReq keys are still quite a magical thing to me. The use I make of them the most is rebooting a Linux hung up machine even when it all seems lost.
For our specific case, we are going to be looking at the SysReq Key "g":
If the in-kernel debugger kdb is present, enter the debugger.
In order to not have to activate all the SysReq requirements to be able to press the alt+SysReq+KEY combination every time I boot, I created a file named kgdb_commands. Such file contains:
echo ttyS1,115200 > /sys/module/kgdboc/parameters/kgdboc
echo g > /proc/sysrq-trigger
The first command we know, the second will trigger the "g" functionality and enter the debugger which is now configured to send the information to our /dev/ttyS1 serial port.
Bear in mind that these commands should be run as root!
sudo bash -f kgdb_commands
After doing so, on the client machine after loading gdb and our sources, we run:
target remote /dev/ttyS1


On the following image we can see the outcome of setting a breakpoint on a certain function as per the exploit:


Conclusion

Always go back in time and think: What would've a Sysadmin do 10 years ago? And for sure an answer will be there waiting for you. Be it in the way of Serial Ports, Terminals or SysReq keys!

Further References