L3akCTF 2024 - [REV] Angry
Difficulty : ⭐
Decompilation with Ghidra
I used Ghidra to decompile the angry_patched_skill_issues binary.
The main()
function is called FUN_001017c7
. I decompiled it :
It seems that the program asks the user to give a password and does some stuff.
Then, it compares return value of FUN_0010120d
with 0 :
- If it is 0, it prints “Bruh :(\n” to stdout using
puts()
function. - Else, it prints “Congratulations !”
Concolic execution with Angr
Because I’m lazy, i used dynamic symbolic analysis with angr module :
import angr,sys
def main():
proj = angr.Project('angry_patched_skill_issues')
init_state = proj.factory.entry_state()
simulation = proj.factory.simgr(init_state)
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution = simulation.found[0]
print('flag: ', solution.posix.dumps(sys.stdin.fileno()))
else:
print('no flag')
def is_successful(state):
return b"Congratulations !\n" in state.posix.dumps(sys.stdout.fileno())
def should_abort(state):
return b"Bruh :(\n" in state.posix.dumps(sys.stdout.fileno())
main()
Flag ?
And after 9 seconds I had this result :
Here is the return of angr :
\xbe3A\x01\x01angr_4_l\xfff3_d0nt_do_i\x02_m4nU4lly}\x00\x00
Because it is L3akCTF, each flag starts with “L3AK{” and ends with “}”. Knowing this information, I replaced non-printable ascii chars with a dot “.” and here is the result :
L3AK{angr_4_l.f3_d0nt_do_i._m4nU4lly}
I’m missing two printable ascii characters to win. Bruteforcing time !
Bruteforcing flag
import time
import subprocess
final = []
a = time.time()
for i in range(32,127):
for j in range(32,127):
crafted_flag = "L3AK{angr_4_l"+str(chr(i))+"f3_d0nt_do_i"+str(chr(j))+"_m4nU4lly}"
ps = subprocess.Popen(('echo', crafted_flag), stdout=subprocess.PIPE)
output = subprocess.check_output(("./angry_patched_skill_issues"), stdin=ps.stdout)
if(b"Congratulations !" in output):
final.append(crafted_flag)
ps.terminate()
print(f"Finished in {time.time()-a} second(s)")
print(f"{len(final)} possible flag(s) found")
Wait… what ? It seems that these 2 bytes can hold any value…
Guessing the flag 🤨
If I use 100% of my brain, I can guess the flag. Indeed, it is partially written in hexspeak.
I’m thinking of these flags :
angr_4_l.f3_d0nt_do_i._m4nU4lly -> angr_for_life_dont_do_it_manually
"l.f3" (life) -> ["lif3","lIf3","l1f3"]
"i." (it) -> ["it","iT"]
There are 6 possibilities… This final flag worked :
L3AK{angr_4_l1f3_d0nt_do_it_m4nU4lly}