Description
What's behind the numeric gate? Download gatekeeper, reverse the numeric checks, and enter the one 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
Walk me through it- Step 1Run the binaryExecute 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
./gatekeeperLearn 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 2Send -1 as the inputThe binary uses an unsigned comparison on a signed integer, so
-1wraps to0xFFFFFFFFwhen re-read asuint32_tand passes the gate. Replace<PORT_FROM_INSTANCE>with the port shown on the picoCTF instance launch page (next to the host).bashecho '-1' | ./gatekeeperbash# Or on the remote instance:bashecho '-1' | nc <HOST> <PORT_FROM_INSTANCE>Learn more
This is a signed/unsigned integer confusion vulnerability, also called type confusion or an integer signedness bug. In C,
-1stored in a signed 32-bit integer (int) has the bit pattern0xFFFFFFFF. Reinterpreted asunsigned int, that bit pattern is 4,294,967,295 (all-ones in 32 bits = 232 - 1), the largest unsigned 32-bit value, far greater than any positive number a sane threshold would pick.The vulnerable pattern in this binary is essentially:
if (input > THRESHOLD)whereinputwas read as a signed int but the comparison promotes both sides to unsigned. Any positive input you try (like5,100, or1000) takes the failing branch because it really is less thanTHRESHOLD. Only a negative number wraps to something larger thanTHRESHOLDafter the unsigned promotion, and-1wraps to the maximum.Integer signedness bugs appear throughout real-world security vulnerabilities. MITRE CWE-195 (Signed to Unsigned Conversion Error) and CWE-196 (Unsigned to Signed Conversion Error) catalogue this class. Famous examples include the MS04-011 LSASS buffer overflow and vulnerabilities in OpenSSH and PHP's integer handling. Compilers warn about signed/unsigned comparisons with
-Wsign-compare; always enable it. For the broader context on integer-class bugs in pwn challenges, see the buffer overflow guide. - Step 3Read the flagThe gate opens and the binary prints the flag directly.
Learn more
Integer type bugs are among the oldest and most pervasive vulnerability classes in C and C++ code. They are particularly dangerous because they often lead to memory corruption (out-of-bounds reads and writes) in addition to logic bypass. A negative array index like
buf[-1]accesses memory before the buffer, which often lands in other stack variables or heap metadata.Modern defences include compiler sanitisers (
-fsanitize=signed-integer-overflow,-fsanitize=unsigned-integer-overflowin Clang), static analysis tools (Coverity, CodeQL), and rigorous code review. Memory-safe languages like Rust eliminate this entire class by making integer overflow a compile-time check (in debug mode) or well-defined wrapping (in release mode with explicitwrapping_add). In Rust you cannot accidentally treat a signed integer as unsigned in a comparison.
Flag
picoCTF{g4t3k33p3r_byp4ss_...}
The gatekeeper checks the input with a signed/unsigned integer mismatch - passing -1 satisfies the unsigned comparison and bypasses the gate.