Description
What's behind the numeric gate? You only get access if you enter the right kind of number. Download gatekeeper, reverse the numeric checks, and enter the value that passes.
Setup
Download the binary and make it executable.
Run it and observe what kind of input it expects.
chmod +x gatekeeper./gatekeeperSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Run the binaryObservationI noticed the challenge provides a compiled binary named gatekeeper with no source, which suggested the first step is to run it directly so that its prompts and error messages reveal what kind of input it expects before committing to disassembly.Execute gatekeeper and read the prompt. It asks for a number, and internally checks it against a threshold using an unsigned comparison on a signed input.bash./gatekeeperWhat didn't work first
Tried: Running strings on the binary hoping to find the flag or the expected numeric value in plaintext.
strings prints readable text sequences from the binary, but the flag is only produced at runtime by reading a server-side file - it does not exist inside the binary. The numeric threshold may appear as a constant, but without understanding the base-conversion logic you still cannot craft the right input, so strings alone leaves you stuck.
Tried: Entering a normal 4-digit decimal number like 1000 to satisfy the 'greater than 999' check.
The binary also enforces a string-length check of exactly 3 characters. A decimal 1000 is 4 characters long and fails the length gate immediately, printing an error before the numeric comparison is ever evaluated. You need a representation that is simultaneously 3 characters and decodes to a value above 999.
Learn more
When approaching an unknown binary, always start by running it with normal input to understand its interface. The program's prompts, error messages, and exit codes give you immediate information about what it expects. In this case the binary asks for a number, which suggests it performs integer comparisons internally.
If the binary doesn't reveal enough from runtime behaviour, the next steps are static analysis (disassembling with
objdumpor Ghidra, or reading the source withstrings/cat) and dynamic analysis (running understraceto see system calls, orltraceto see library calls). For this challenge the vulnerability class (integer type confusion) is inferable from the prompt alone and confirmed quickly.Step 2
Send a 3-digit hex number greater than 999 decimalObservationI noticed the binary enforces a 3-character length limit AND a numeric threshold above 999, two constraints that no decimal integer can satisfy simultaneously, which suggested that the conversion must accept hex so that a 3-character value like '3e8' encodes 1000 decimal.The binary reads the input as a string, checks the string length must be 3, and separately converts it to a long integer that must be greater than 999. Connect to the server and send a 3-character hex value like3e8(hex for 1000). The program accepts hex via strtol.bashecho '3e8' | ./gatekeeperWhat didn't work first
Tried: Sending '0x3e8' (with the 0x prefix) instead of bare '3e8' to make the hex value explicit.
The binary reads exactly 3 characters via a %3ls format specifier. '0x3e8' is 5 characters, so scanf truncates it to '0x3', which strtol in base 16 parses as 0x03 = 3 decimal - far below the 1000 threshold. The 0x prefix is not needed because strtol is already called with base 16 hardcoded.
Tried: Trying strtol with base 0 and sending a string like '0x' prefix to auto-detect hex.
The disassembly shows the base argument to strtol is hardcoded to 16, not 0. Base 0 would only work if the binary used auto-detection, which it does not. With a hardcoded base of 16, '3e8' is parsed correctly without any prefix, and any prefix characters would just eat into the 3-character budget.
Learn more
In Ghidra, the main function reads input with scanf using a
%3lsformat (limiting to 3 characters). It then converts the string with a base-16 parse (e.g.strtol(input, NULL, 16)), so a bare 3-character hex string like3e8(no0xprefix needed) becomes 0x3e8 = 1000 decimal. The conversion must be base 16: with base 0,strtolwould treat3e8as decimal and stop at thee, yielding just 3. The binary checks two conditions: string length must be 3, AND the numeric value must be between 1000 and 10000.Hex digit strings like
3e8(3 characters) decode to 1000 decimal, satisfying both constraints simultaneously. This is why the hint says "reversing the string and cleaning out extra text may help you recover the flag."Step 3
Decode the reversed and obfuscated flag outputObservationI noticed the binary's output contained repeated 'picoCTF_' substrings interspersed through what looked like a scrambled flag, which suggested the reveal_flag function was printing the flag in reverse with 'picoCTF_' inserted at intervals, requiring a strip-then-reverse post-processing step.The reveal_flag function prints the flag content in reverse order, with 'picoCTF_' (inserted forward by the function) interspersed every 4 characters. Strip the 'picoCTF_' occurrences from the raw output, then reverse the remaining string to get the real flag.bash# Copy the output from the binary, strip out the 'picoCTF_' interspersed textbash# Then reverse what remains to read the flagbashecho '<output>' | sed -e 's/picoCTF_//g' | revbash# Or: paste the output into Python and process itpythonpython3 -c "output = '<paste output here>'; print(output.replace('picoCTF_', '')[::-1])"Expected output
picoCTF{g4t3k33p3r_...}What didn't work first
Tried: Reversing the raw binary output directly without first stripping the interspersed 'picoCTF_' substrings.
The reveal_flag function inserts 'picoCTF_' forward every 4 characters while printing the flag backwards, so a plain rev of the full output produces a garbled string with 'picoCTF_' fragments scattered throughout. You must remove all occurrences of 'picoCTF_' first, then reverse, to recover the clean flag.
Tried: Using strings on the binary output file or piping the binary's stdout directly to grep for the flag format.
The flag is not printed in its final form - it is interleaved and reversed on the fly. grep 'picoCTF{' on the raw output will not find a match because the opening brace appears only after you apply both the strip and reverse transformations. You need to post-process the output rather than search it verbatim.
Learn more
The
reveal_flagfunction in this binary opens the flag file and prints it backwards, inserting the string "picoCTF_" (forward) every 4 characters as additional obfuscation. To recover the real flag: strip the repeatedpicoCTF_interleaving and reverse the remaining characters.This two-layer obfuscation (reversal + interleaving) is a common CTF technique to prevent straightforward string extraction with
strings. The hint in the challenge description explicitly tells you to reverse the string and clean out extra text.
Interactive tools
- Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
- Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
Flag
Reveal flag
picoCTF{g4t3k33p3r_...}
Send a 3-character hex value greater than 999 decimal (e.g. '3e8' = 1000). The flag output is reversed and obfuscated with interspersed 'picoCTF_' text - strip that and reverse to get the real flag.