Previous Post in Series:
- [Linux Kernel Exploitation 0x0] Debugging the Kernel with QEMU https://blog.k3170makan.com/2020/11/linux-kernel-exploitation-0x0-debugging.html
- [Linux Kernel Exploitation 0x1] Smashing Stack Overflows in the Kernel https://blog.k3170makan.com/2020/11/linux-kernel-exploitation-0x1-smashing.html
- this post
Controlling EIP (No Canary)
|GDB output showing that an address from our payload is actually executed in the kernel! We officially control execution woo hoo!|
./stacksmash_app.elf `python -c '\
address_string="".join([chr(int(address[2:][i:i+2],16)) for i in range(0,len(address[2:])+2,2) if len(address[2:][i:i+2]) != 0][::-1]);print("A"*int(sys.argv)+address_string)' $LENGTH $ADDR` 10
Privilege Escalation for Kernel Intruders
- prepare_kernel_creds(struct task_struct *daemon) is a function that generates a cred structure. We need this for our call to the next important function. I know it takes a weird task_struct thing but fret not, the documentation indicates that this can be NULL, which will essentially trigger some default option that gives us "full creds".
- commit_creds(struct cred *) this function does the actual deed and installs the cred structure to our task.
- an instruction chain that puts a null in rdi before we call prepare_kernel_creds. This is because according to calling convention rdi holds the first parameter.
- an instruction chain that grabs the returned cred structure---which will be a pointer in rax at this point---, and sticks it in rdi before our call to commit_creds
- RIP Control: Find a write length that controls the RIP
- ROP Chain: Build a ROP Chain that calls commit_creds(prepare_kernel_creds(0))
- Return2Userland: Exit the kernel safely using iretq, sysexit, etc
Building a ROP chain
- 0xffffffff8124529d pop rbx ; ret
- 0xffffffff8230f2ff call rbx
Using these gadgets means we essentially want to pop something into rbx, this requires us to then have somethin on the stack; for us this means packing in an address to the prepare_kernel_creds call, which would look like this basically:
[AAA...*48][0xffffffff8124529d][prepare_kernel_creds][0xffffffff8230f2ff]Okay so we need to somehow use ./stacksmash_test_addr.sh to pack two addresses into the payload, I've tried more sophisticated ways and they are currently failing so I've decided to stick with this clunky script for now. Anyway here's how you stuff more than one address into the payload, call stacksmash_test_add.sh as follows:
|Some gdb output confirming we actually are building a sane payload. Here I just grab the address the buf parameter from a kernel mediated call to vfs_write, this helps me make sure I'm looking at the correct buffer, before the driver touches it.|
And if you manage to actually run the sample payload here you should hit breakpoints that indicate you're in control:
That confirms that we are hitting the right notes and we can pretty much call any function now with this neat little gadget! What we need to do now is prepare a ROP chain to stick a NULL in rdi before we make the call to preapre_kernel_cred. And just a note when choosing gadgets I would prioritize those that cause the least stack drama---some ret instructions specify an offset with which to bump the return address so watch out---, affect as little registers as possible. But I suggest just trying stuff, you actually learn a lot from seeing gadgets not work!
I've been stuck at this point for a few weeks so I'm going to cut my losses with this post and end it here we'll prepare the rest of the payload in the next post. Enjoy!
Reading and References