Description
Hm, this is a weird binary. Answer the password to get the flag. Connect to the service. The binary is compiled from Go, so its disassembly is large and unusual, but the check logic reduces to a 32-character password validated by an XOR comparison plus an MD5 check.
Setup
Connect via netcat and provide the correct password.
nc mercury.picoctf.net <PORT_FROM_INSTANCE>Solution
Walk me through it- Step 1Identify the XOR encoding in the Go binaryLoad the binary in Ghidra. Because it is a Go binary the symbol/string layout is dense, but the relevant routines are still named: find check_password. It XORs the input with a hardcoded hex string and compares the result to a local variable. Separately, an 'ambush' function takes the MD5 of the password and compares it to another hardcoded hash.bash
ghidra gogobash# Go binary: the symbol table is large; search for check_password, ambush,bash# and the long hardcoded hex string in the disassembly.Learn more
The binary has two validation layers (the Go runtime makes the disassembly noisy, but the check itself is simple):
- The check_password function XORs the 32-character input with a hardcoded hex string and checks the result.
- The ambush function takes the MD5 of the password and compares it to a hardcoded hash.
The key insight from using GDB: set a breakpoint just before the XOR comparison and dump the stack. The expected XOR value is visible at a specific stack offset (sp+4 and sp+24).
- Step 2Use GDB to read the XOR key from the stackSet a breakpoint inside check_password at the comparison point. Run the binary with any 32-character input. At the breakpoint, dump the stack to find the hardcoded XOR target. Then XOR it with the hex string from the disassembly to recover the expected password.bash
gdb -q ./gogobash(gdb) break *0x80d4b30bash(gdb) runbash# Enter any 32-character input when promptedbash(gdb) x/32bx $sp+4bash(gdb) x/32bx $sp+24Learn more
The password must be exactly 32 characters long. When the breakpoint fires,
$sp+4contains the hardcoded hex string from the disassembly and$sp+24contains the XOR target. XOR these together to recover the plaintext password. - Step 3Recover the password with Python and look up the MD5XOR the two values from GDB using Python to get the plaintext password. Then use the MD5 lookup from the ambush function to confirm. The MD5 hash resolves to 'goldfish'.python
python3 << 'EOF' from pwn import unhex, xor # Values from GDB dump at sp+4 and sp+24 hex_string = bytes.fromhex("PASTE_FROM_DISASSEMBLY") xor_target = bytes.fromhex("PASTE_FROM_SP+24") password = xor(hex_string, xor_target) print(password.decode()) EOFbash# The password is: goldfishbashnc mercury.picoctf.net <PORT_FROM_INSTANCE>bash# Enter: goldfishLearn more
The MD5 hash in the ambush function can be looked up on crackstation.net or similar MD5 rainbow table sites. The hash corresponds to "goldfish". Entering this password at the netcat prompt prints the flag.
The flag format for this challenge is not the standard
picoCTF{...}- the binary prints a key directly. The challenge description confirms the flag is non-standard.
Flag
picoCTF{...}
XOR the input with the hardcoded hex string and find the MD5 preimage (goldfish) to get the correct password, which unlocks the flag.