- 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
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.
SMEP, SMAP, KPTI and KASLR are all enabled.
CONFIG_STATIC_USERMODEHELPER=y is set, so
modprobe_path is readonly.
Each node has a pointer to next node, pointer to chunk that holds data and size
The request struct passed to ioctl is self-explanatory
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
The bug is in k32_create:
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 :)
- Allocate a bunch of nodes with
k32_createand use OOB read in
k32_read, to leak heap by reading a freelist pointer
seq_operationsstructs and leak code address
- Create ropchain that performs
msg_msgstructs having said ropchain in msg buffer
.nextfn pointers in
seq_read_iter, which executes code form the
.nextfn pointers are set to ret gadgets so as to misalign the stack
seq_read_iterreturns, 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.
It was fun making this challenge. Hope it was fun to solve it as well :D
You can find the full exploit here