Tags: emulator kernel pwn
Rating:
As description states, this challenge pretty much contains a userland binary, a kernel binary, and an emulator (written using the unicorn engine emulator framework) that emulates the userland and kernel together.
You can find the final exploit script here.
The userland binary is a brainfuck interpreter. In brainfuck, you have whats called a data pointer that you can shift forwards and backwards using the >
and <
operators respectively. The data pointer in the userland binary pointed to a stack buffer, and there were no bounds checks on the >
and <
operators, so you could shift the data pointer up the stack to the return address and modify it. This was the userland bug you could use to craft your ROP chain on the stack and return to it.
Once you have code execution in the userland, you can talk to the kernel. The kernel was also a very small binary. Only the sys_read
, sys_write
, and sys_open
system calls were implemented. sys_open
had a stack buffer overflow where it copied the filename from userland to a kernel stack buffer without doing any bounds checking. The only catch was that the copy would stop at null bytes, so I had to find a nice way to ROP, map a page as RWX for shellcode, read shellcode into it, and finally jump to the shellcode.
Once you have code execution in the kernel, you are able to call malloc
and free
inside the emulator at will through the int 0x71
interrupt. You are only ever allowed access to one malloc'd chunk at a time, and when freeing the chunk, the pointer is not zeroed, which results in a UAF. You are also allowed to read / write the chunks contents at will (any size), which can be used for a heap overflow (although I didn't do that).
I first used the UAF to leak a libunicorn.so.1
address, then I did a tcache dup attack to leak the address of vasprintf@LIBC
from the GOT of libunicorn
, and finally I did a second tcache dup attack to overwrite __free_hook
with system
to get a shell.