zer0pts CTF
pwn
Actually it's not baby :P
This is the only challenge the source code isn't attached among pwn tasks. The program is so simple that you can understand even only with objdump.
It has BOF as the title says. read
accepts 0x200 bytes even though the buffer size is 0x20.
There're only 3 functions: setbuf
, exit
, read
. We can call only these 3 fnuctions from plt. No leak.
setbuf
is used to disable buffering of stdin, stdout and stderr, which is common in pwn tasks.
Because of the small binary, there's only few gadgets.
Our first goal is to get leak by _IO_2_1_stdout_
. Since PIE is disabled, we can use stdin, stdout, stderr pointers written in the .rela.dyn
section. This time we use them to overwrite _IO_write_ptr
in _IO_2_1_stdout_
.
Even if we could overwrite _IO_write_ptr
, we can't leak anything as we don't have any write-related functions. In order to force it flush, we have to call _IO_overflow_t
.
In order to resolve this we use exit
function. Inside exit
calls __run_exit_handlers
, which finally calls _IO_cleanup
. It frees stdin, stdout and stderr, and flushes the buffer which has unprinted data by calling _IO_overflow_t
.
So, calling exit
will leak the libc address! The END?
It's not that easy. exit
quits the program.
In libc 2.23, we can forge the vtable of _IO_FILE
. So, we can change the vtable to somewhere like bss instead of _IO_jump_t
, and can forge function pointers so that the attacker can take control when exit
is called. Since exit
calls _IO_overflow_t
, which enables us to call main
again. The END?
No way. If we change _IO_2_1_stdout_->_IO_overflow_t
, now we can't leak any address. We use stderr
to resolve this problem. stderr, stdout and stdin are linked to _IO_list_all
in this order. Thus, if we change _IO_2_1_stderr_->_IO_write_ptr
and the vtable of stdout, the free process of stderr will ignite first, which leaks the libc address and stdout vtable will call main
again.
Be noticed in order to make _IO_2_1_stdout_->_IO_overflow_t
ignite we need to forge _IO_2_1_stdout_->_IO_write_ptr
as well. In this way, we can leak the libc address with connection kept. (You cannot use stdout and stderr after that because it's broken.)
Try hard to write your exploit.