r0hanSH (CLS)

Hello friend, I made this blog to document my journey into infosec. It includes my CTF writeups, bugs I found in real-world applications, some tips and much more.

Home whoami

InCTF 2019

23-09-2019

TIC_TAC_TOE (RE)

It was a 4x4 tic-tac-toe game. Even after winning the game, you don’t get flag. So I analysed the disassembly and got to know if game is draw between you and machine, it calls an interesting function. Enjoy the code

import angr
import claripy

p = angr.Project("/bin/true")
state = p.factory.entry_state()

flag_nums = [claripy.BVS("flag_%d" % i, 64) for i in range(16)]

xor_key = '!@#sbjhdn5z6sf5gqc7kcd5mck7ld=&6'

"""
Value of tiles for Player
0a 0b 0c 0d
0e 0f 10 11
12 13 14 15
16 17 18 19

Value of tiles for MACHINE
1a 1b 1c 1d
1e 1f 20 21
22 23 24 25
26 27 28 29

flag_nums follows pattern -> player_move, machine_move, player_move, machine_move, ...
"""


for i in range(0, 16, 2):
	state.solver.add(flag_nums[i] >= 0xa, flag_nums[i] <= 0x19)
	state.solver.add(flag_nums[i+1] >= 0x1a, flag_nums[i] <= 0x29)

tmp1 = []
for i in flag_nums:
	tmp1.append(i*8)
	tmp1.append(i*7)

check = []
for i in range(len(xor_key)):
	check.append( ord(xor_key[i]) ^ tmp1[i] )

a1 = [0x9b, 0xcf, 0x1db, 0x1b9]
a2 = [0xf9, 0x174, 0x27f, 0x1a7]
a3  = [0xCE, 0xB1, 0xA, 0x1B]
a4 = [0xBF, 0x9B, 0x1F1, 0x7E]
a5 = [0x37, 0x5D, 0x11D, 0x14B]
a6 = [0x104, 0x1B3, 0x3A4, 0x22A]
a7 = [0xAD, 0xB7, 0x99, 0x9E]

a8 = [0xC9, 0x0E1, 0x121, 0x169, 0x1A, 0x0D, 0x0A1, 0x7F, 0x7, 0x9, 0x157, 0x116, 0x0B9, 0x0B8, 0x15D, 0x86, 0x8C, 0x0DF, 0x161, 0x0B3, 0x0FFFFFFF8, 0x0FFFFFFEF, 0x167, 0x80, 0x17, 0x0FFFFFFF6, 0x119, 0x79, 0x84, 0x82, 0x66, 0x9A]

for i in range(len(tmp1)):
	state.solver.add(tmp1[i] <= 400)

for i in range(4):
	state.solver.add(check[i]^check[i+4] == a1[i])
	
	state.solver.add(check[i+8] + check[i+8+4] == a2[i])

	state.solver.add(check[i+8*2] - check[i+ 8*2 +4] == a3[i])

	state.solver.add(check[i+8*3] ^ check[i+ 8*3 +4] == a4[i])

	state.solver.add(check[i+ 8*3 +4] ^ check[i] ^ check[i+4] == a5[i])

	state.solver.add(check[i+ 8*2 +4] + check[i+8] + check[i+8+4] == a6[i])

	state.solver.add(check[i+8] ^ check[i] ^ check[i+4] == a7[i])

flag_tiles = [state.solver.eval(i) for i in flag_nums]

print flag_tiles[::]

tmp2 = []
for i in flag_tiles:
	tmp2.append(i*8)
	tmp2.append(i*7)
flag = ""
for i in range(len(tmp2)):
	tmp3 = tmp2[i] ^ (i + a8[i])
	if tmp3 > 127:
		flag += 'X'
	else:
		flag += chr(tmp3)
	
print flag

Few chararcters were missing, but we can find it using state.solver.max() and test them. But while passing result of flag_tiles to program running inside debugger, it gives us flag.

Branching

FLAG : inctf{w0W_Y0u_cr4ck3d_my_m3th0d}