We are provided a stripped 64 bit ELF binary in this challenge. Reversing the binary is pretty easy due to its small size, I started from main and then went through all the functions i encountered.

Initial Analysis

First of all binary queries the size of the file “flag.txt” with __xstat function and then allocates memory equal to the size of the file + 33. After this in “sub_B1C” , 32 bytes are read from “/dev/urandom”  byte by byte, the binary makes sure that the read byte is smaller than 0x5F (which is derived from sub_930). The above read bytes are then used as index in the following string: “qwertyuiop[]\\asdfghjkl;’zxcvbnm,./`1234567890–=~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\”ZXCVBNM<>?”  

Then a string of length 32 is generated using the above method. The next function (sub_BBD) reads the flag from flag.txt and then concats this flag to the above generated random string. Now the binary multiplies the length of the whole string and multiplies it with 7 to generate a number, Remotely the number generated is 364 which can help us determine the length of the flag remotely which turns out to be 20. Also we have 364 tries to guess the flag which is too less so I proceed to analyse the rest of binary. With some dynamic analysis, we know how the binary checks our input with the string in memory.

So if our entered character is less than the char in memory then 1 is returned, if it is greater then -1 is returned and if they are equal then it returns (index + 1) % 16. This reminded me of binary search which would have guessed the flag in less than 364 tries. Also one important thing is if we enter a string more than 1 char then it checks all the chars one by one similarly, so it was clear that binary search was a solid strategy to solve this challenge and i proceeded to write the script.

from pwn import *

array = "qwertyuiop[]\\asdfghjkl;'zxcvbnm,./`1234567890--=~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"
array = ''.join(sorted(array))
flag = ""
#rem = process("./fastflag")
rem = remote("fastflag-28659598.challenges.bsidessf.net", 9999)

k = 2

def binary(string, l, r):
	rem.recvuntil("> ")
	mid = (l+r)/2
	rem.sendline(flag + string[mid])
	res = rem.recvline()[:-1]
	res = int(res.split("[")[1].split("]")[0])
	if res == k:
		return string[mid]
	elif res < 0:
		return binary(string, l, mid - 1)
	return binary(string, mid + 1, r)

# guess the 32 random chars
for i in range(32):
	a = binary(array, 0, len(array))
	flag += a
	print flag
	if k > 16:
		k = 1

array = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

# guess the flag
for i in range(33):
	a = binary(array, 0, len(array))
	flag += a
	print flag
	if k > 16:
		k = 1

print flag

So after running the above script we get the following output which also displays the flag.


The flag is CTF{binary_search_7}

Categories: CTFs