tl;dr
- Giving size > 48 causes heap OOB r/w of 16 bytes
- Use OOB r/w get leaks and overwrite objects for rip control
Challenge Points: 1000
No. of solves: 1
Challenge Author: k1R4
Challenge Description
32 bytes is all you get, or is it? :-O
Handout has the files bzImage, rootfs.cpio, run.sh and pow.py(for PoW). Typical for a kernel challenge.
Initial Analysis
SMEP, SMAP, KPTI and KASLR are all enabled. CONFIG_STATIC_USERMODEHELPER=y
is set, so modprobe_path
is readonly.
Structs
1 | typedef struct{ |
Each node has a pointer to next node, pointer to chunk that holds data and size
1 | typedef struct{ |
The request struct passed to ioctl is self-explanatory
Functionality
We have 4 commands in accessible through ioctl
- k32_create - create a node
- k32_delete - delete a node
- k32_read - read data from a node
- k32_write - write data to a node
Bug
The bug is in k32_create:
1 | static noinline uint8_t k32_fix_size(uint8_t size) |
req->size is updated with the fixed size. However when its passed to kmalloc, its fixed again with k32_fix_size.
Finally node->size is set to req->size. So giving size > 48 will cause node->size = 48 but will kmalloc a chunk of size 32 (kmalloc-32), hence the challenge name k32 :)
Exploit Strategy
- Allocate a bunch of nodes with
k32_create
and use OOB read ink32_read
, to leak heap by reading a freelist pointer - Spray
seq_operations
structs and leak code address - Create ropchain that performs
commit_creds(prepare_kernel_cred(0))
- Spray
msg_msg
structs having said ropchain in msg buffer - Overwrite
.start
and.next
fn pointers inseq_operations
usingk32_write
- Call
read()
to triggerseq_read_iter
, which executes code form the.start
and.next
fn pointers .start
and.next
fn pointers are set to ret gadgets so as to misalign the stack- When
seq_read_iter
returns, RIP is popped from userspace saved registers down the stack - This allows us to pivot to heap where our ropchain is saved
- Ropchain is executed and finally returns to userland where root shell is popped.
Conclusion
It was fun making this challenge. Hope it was fun to solve it as well :D
You can find the full exploit here
Flag: bi0sctf{km4ll0c-32_1sn't_3xpl01tabl3_r1gh7_guy5?_3feb178d2a9c}