The file is a GO binary. After locating the main function, by stepping in the debugger, I found that the binary expects a command line argument of 42 characters.
For each character it calls a sub-routine sub_47B760 that returns a calculated byte corresponding to the one supplied. This byte is then compared to the one it corresponds to in a hardcoded array of bytes, which clearly represents the encrypted flag.
I didn't really look into how the values are calculated since GO binaries tend to be messy and I didn't really have to do it in order to solve the challenge. The thing is, the program branches to the block that displays the fail message ("Nope") as soon as it finds that one character is wrong. This opens room for brute-forcing since we can brute-force the flag character by character dynamically.
I used python with GDB to do so. Here's the solution script :
full script : here
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#HXP CTF 2017 - dont_panic 100 pts | |
#Writeup link : https://rce4fun.blogspot.com/2017/11/hxp-ctf-2017-dontpanic-reversing-100.html | |
#Souhail Hammou | |
import gdb | |
CHAR_SUCCESS = 0x47B976 | |
NOPE = 0x47BA23 | |
gdb.execute("set pagination off") | |
gdb.execute("b*0x47B976") #Success for a given character | |
gdb.execute("b*0x47BA23") #Block displaying "Nope" | |
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-+*{}'" | |
flag = list('A'*42) #junk | |
for i in range(0,len(flag)) : | |
for c in charset: | |
flag[i] = c | |
# the number of times we need to hit the | |
# success bp for the previous correct characters | |
success_hits = i | |
gdb.execute("r " + '"' + "".join(flag) + '"') | |
while success_hits > 0 : | |
gdb.execute('c') | |
success_hits -= 1 | |
#we break either on success or on fail | |
rip = int(gdb.parse_and_eval("$rip")) | |
if rip == CHAR_SUCCESS: | |
break #right one. To the next character | |
if rip == NOPE: #added for clarity | |
continue | |
print("".join(flag)) | |
#flag : hxp{k3eP_C4lM_AnD_D0n't_P4n1c__G0_i5_S4F3} |
After a minute or so, we get the flag.
No comments:
Post a Comment