Description
This binary is putting together some important piece of information... Can you uncover that information? Examine this file. Do you understand its inner workings?
Setup
Download the binary, make it executable, and load it in Ghidra to understand the overall structure.
Have GDB available for dynamic analysis to read the flag at runtime.
wget https://artifacts.picoctf.net/c_titan/187/bin && \
chmod +x binSolution
Walk me through it- Step 1Understand the structure in GhidraIn Ghidra, find main and look at the decompiled output. It performs many C++ string concatenations (the += operator calls) to build the flag character by character. Near the end of main, there is one final append of a closing curly brace, followed immediately by the first destructor call. The string's value is complete at that point and lives in the object returned in RAX.
Learn more
Ghidra is a free, open-source reverse engineering framework from the NSA. Its decompiler shows C++ string concatenation as
operator+=calls, which is verbose but identifies where characters are being assembled. The key forensic marker here is the append of the closing}character: after that call the flag string is complete, and the first destructor call immediately follows. That boundary is your breakpoint target in GDB.The binary address for main starts around
0x001011...in Ghidra. ASLR changes the high bytes at runtime, but the last four hex digits are stable; use those to find the matching instruction in GDB. Look for the address just after the final+=and just before the first~basic_stringdestructor call. - Step 2Break in GDB and read RAXRun the binary in GDB. Set a breakpoint at the address of the instruction immediately after the last operator+= (the closing-brace append) and before the destructor call. When execution stops, examine RAX as a pointer to a C++ string; the flag bytes are readable there.bash
gdb ./binbash(gdb) break *0x<last_four_from_ghidra>bash(gdb) runbash(gdb) x/s $raxx/s $raxprints RAX as a null-terminated ASCII string. You should see the fullpicoCTF{...}. If you see a pointer address rather than the string, tryx/s *$raxto dereference one level, or examine the object members withp (char *)$rax.Learn more
In the x86-64 calling convention,
RAXholds the return value of the most recently called function. After the final operator+= call, the C++ string object (or a pointer to it) lives in RAX.x/sin GDB interprets the address as a pointer to a C-style string and prints characters until the null terminator.The flag bytes are ASCII text stored contiguously in heap memory allocated by the C++ string's internal buffer. Even without knowing the exact memory address ahead of time, reading RAX immediately after the last string operation reliably lands on the completed flag.
Dynamic analysis (running the binary with a debugger) complements static analysis (reading disassembly). Static analysis maps the structure; dynamic analysis reads runtime values. For binaries that construct data programmatically, dynamic analysis is usually the fastest path to the answer.
Flag
picoCTF{...}
The flag is unique to your downloaded binary. Read it from RAX just before the first destructor runs in GDB.