sobota, 24 kwietnia 2021

Returning root to userland

Since last few days I was reading a little bit more about kernel exploitation. One of the resources I found[1,2,3] was "good enough" (for me ;)) to follow it and recreate the steps on my own VM machine. Vulnerable challenge - described here by Midas - was a one presented on hxpCTF 2020 - 'kernel-rop'. Below you'll find a "quick autopsy" (but I like to think about it like a note for the 'future me' ;)). Here we go...

Today we'll start here:


As you can see - following the original post we can easily recreate the VM environment. For my case I used Ubuntu 20 on VirtualBox. As I installed a fresh and clean VM - next step for me was to update it to install 'qemu' packages.

After a while we should be here:


Settings for qemu (see: run.sh file) are described in the original post (so I'll not duplicate it here).
If you're looking for more details about kernel debugging I'll recommend you go(ogl)ing deeper. ;)

So far - we are here (below is my modified run.sh file):


Running script and we are here:


To run qemu ('as root') I extracted the image (using extract-image.sh script) and changed the content of ./etc/inittab file (change uid from 1000 to 0 and run compress.sh and run.sh to verify it).

Then you can see (when we are already a root user) we are able to check /proc/kallsyms file. (As the normal user we won't be able to do it for this challenge but you can use this 'hack' to verify the values of the address later or in the meantime if you want... and restore it back (to uid1000) when you need to check your final exploit).

After reading the post I decided to summarize it a bit: what is the attack scenario here, what should be known before the attack, and so on.

If you are familiar with vulnerabilities exploited by "returning to shellcode" it should be easier to understand the steps we need to take to reproduce the attack here. It is pretty similar case (but this time for the kernel ;)).
 
If you're not familiar with those topics I suggest you to read about it and then go back (to posts by Midas ;) or) here. ;)

 

TL;DR - reading the post (from the backward):

I decided to start preparing poc exploit reading the post from the end - as you'll see: reading it this way we can prepare our skeleton exploit and "fully understand" what is going on on "lower-level" of the poc ('what function_X is doing and what is the purpose of function_Y' and so on). Let's start from the main() function then. ;) 

We should be here:

On the screen (from the original post) you can see few functions. But if you'll check the exploit prepared by the author you'll find there "few more" functions. So I decided to list all of them below, like this:

- save_state()
- open_dev()
- leak()
- print_leak()
- escalate_privs()
- get_shell()
- overflow()
- main() with all defines/'global variables'

Let's see what is the purpose of those functions. We'll start from the first one - save_state() - and another link I found when I was trying to *understand more asm-instructions in the code:

 

*As you can see I added few comments and simple printf's to the code, just in case of my debug/learn process. 

Next function - open_dev():

Here we'll simply "open" the vulnerable kernel/target module to read from it. When "device" is opened we can continue  with next function available in the ret2usr.c poc  - leak() - presented below:

Now we can use our 'opened device' to leak the value at offset 16 and read the cookie value (as it was described in the original post). If you want to check it feel free to uncomment the very next function - print_leak():


Going to the next function - escalate_privs() - we can see more asm code, let's read it:


As it was described by dausynt:


 

So, both //mentioned in the comments// functions we'll need to prepare our way to "privilege escalation". (Sounds like "I spent another 2 days to read more about few other kernel-related-bugs" ;) so the screen above is of course for a different bug but I liked the "obvious" description in the end. ;))

Next: more asm and swapgs? No problem. :) 

Next - we are here - to get_shell()

As the name of the function is pretty straightforward - we'll simply run /bin/sh if we have an UID=0. Our next function is the overflow() - here we'll prepare a final ROP payload and use write() to sent our code to the kernel's module (at least I understood the code like that :P ):


Last function - the main() one (I updated for my super-research-purposes ;)) is presented on the screen below:


Yes, I know - t0t4l 31337. ;> 

Anyway - let's finaly check this poc against "vulnerable (kernel) module" from the CTF! ;) 

Starting qemu:


Checking:

We got it! :D

If you never tried any kernel-related CTF challenge - I must say - it was very interesting one. 

Special thanks goes to Midas (where I found the challenge and original writeup)! Good job and excellent writeup! Thank you. :)

In case you'd like to read few more links about kernel related bugs - few references I used to prepare this 'quick autopsy' you'll find below:

- https://lkmidas.github.io/posts/
- https://www.openwall.com/lkrg/
- https://github.com/MaherAzzouzi/LinuxKernelExploitation
- https://lkmidas.github.io/posts/20210123-linux-kernel-pwn-part-1/
- https://www.kernel.org/doc/html/latest/dev-tools/gdb-kernel-debugging.html
- https://duasynt.com/blog/cve-2014-4699-linux-kernel-ptrace-sysret-analysis


See you next time. ;)


Cheers


 




Brak komentarzy:

Prześlij komentarz