Description
The binary decodes the flag but it takes too long. Speed it up to get the flag.
Setup
Download the binary and make it executable.
wget <url>/need-for-speedchmod +x need-for-speedSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Run the binary and observe the delay
ObservationThe description says the binary takes too long. Run it first and watch exactly how and when it stalls, so the mechanism causing the delay gets identified rather than guessed at.Execute the binary. It will print something like 'Calculating key...' and then hang for a very long time (or use alarm() to kill itself after a few seconds). The actual flag decoding logic is correct - only the artificial delay prevents you from seeing the output.bash./need-for-speedWhat didn't work first
Tried: Running the binary with 'time ./need-for-speed' hoping it would complete if left long enough
alarm(1) delivers SIGALRM after exactly one second and kills the process with a signal; it is not a timeout you can outwait. The busy-wait loop would take millions of seconds, so no amount of patience fixes this at the OS level.
Tried: Using 'strace ./need-for-speed' to trace system calls and spot the delay
strace shows the alarm() syscall and its argument, confirming the timer is there, but strace itself cannot suppress signal delivery. The process still dies from SIGALRM after 1 second; you need a debugger that can handle signals, not just observe them.
Learn more
Binaries can use
sleep(),alarm(), or busy-wait loops to introduce artificial delays.alarm(n)sends SIGALRM to the process after n seconds, killing it by default. These are used in CTF challenges as anti-automation measures.Step 2Use GDB to bypass the SIGALRM timer and get the flag
ObservationRunning the binary, and strace, show an alarm() syscall scheduling a SIGALRM to kill the process after one second. GDB can suppress that signal, which lets the slow calculate_key loop run to completion.Open the binary in GDB. Before running, tell GDB to ignore SIGALRM so the alarm handler never fires. Then simply run the program - the slow calculate_key loop (which counts from 0xec61038e down to 0xd8c2071c and returns 0xd8c2071c as the key) now has unlimited time to complete, and print_flag() prints the flag. An alternate approach is to break at main, call get_key() and print_flag() directly without running the full program flow.bashgdb ./need-for-speedbashhandle SIGALRM ignorebashrunbash# Alternate: call functions directly insteadbash# break mainbash# runbash# call (int) get_key()bash# call (int) print_flag()Expected output
picoCTF{Good job keeping bus #b3a1d39c speeding along!}What didn't work first
Tried: Using 'handle SIGALRM stop' instead of 'handle SIGALRM ignore' in GDB
'handle SIGALRM stop' tells GDB to pause when SIGALRM arrives and then pass it along. The alarm still fires and the process still dies from it; you just get a GDB prompt at the moment of death. 'ignore' is what makes GDB discard the signal and never deliver it.
Tried: Setting a breakpoint on print_flag and running without handling SIGALRM first
GDB forwards unhandled signals to the inferior by default. The alarm fires at one second, SIGALRM kills the process before calculate_key finishes, and the breakpoint on print_flag is never reached. Suppress it with 'handle SIGALRM ignore' before you issue 'run'.
Learn more
The binary calls
set_timer()which invokesalarm(1)- this schedules a SIGALRM to fire after 1 second, killing the program. Thenget_key()callscalculate_key(), which runs a countdown loop from0xec61038edown to0xd8c2071c- far too slow to finish in 1 second. The loop returns0xd8c2071cas the key used to decrypt the flag.handle SIGALRM ignoretells GDB to not stop, not print, and not pass SIGALRM to the program. With the timer defanged, the calculation loop runs to completion andprint_flag()is reached normally. Callingcall (int) get_key()thencall (int) print_flag()is an equivalent shortcut that skips even the timer setup.Step 3Read the flag
ObservationWith SIGALRM suppressed, GDB finishes the run without an early exit. That means print_flag() executed, so the decrypted flag should be sitting in the terminal output.After bypassing the delay, the binary completes its flag decoding and prints it. Copy the output.Learn more
Patching a binary with
xxd+ a hex editor is another approach: find thecall alarminstruction bytes and overwrite them with NOP instructions (0x90). This permanently removes the delay from the binary file.
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{Good job keeping bus #b3a1d39c speeding along!}
The binary kills itself with a SIGALRM timer before the (correct) decode finishes. Bypass the timer rather than racing it: in GDB run `handle SIGALRM ignore` (or set the key directly and call print_flag), then let it complete. The bus-ID hex in the flag is instance-specific.