Static ain't always noise picoCTF 2021 Solution

Published: April 2, 2026

Description

Can you look at the data in this binary? Download static and ltdis.sh.

Download both static and ltdis.sh from the challenge page.

Confirm the binary type before running tools that assume a specific format.

bash
wget <url>/static
bash
wget <url>/ltdis.sh
bash
file static

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Run ltdis.sh on the binary
    Observation
    The challenge provided two downloads, a binary called static and a shell script called ltdis.sh, which suggested the script was specifically designed to extract readable data from that binary and was the intended first step.
    ltdis.sh runs strings -o static (or similar) on the binary and saves output to a .strings.txt file alongside it. Run it, then list the generated text files to find the output filename.
    bash
    bash ltdis.sh static
    bash
    ls *.txt

    Expected output

    picoCTF{d15a5m_t34s3r_...}
    What didn't work first

    Tried: Run strings directly on the binary without ltdis.sh and print to the terminal.

    Running strings static prints thousands of lines to stdout with no output file created. You can still grep the terminal output with a pipe, but ltdis.sh is specifically provided to save the output to static.ltdis.strings.txt for persistent inspection. Skipping the script means missing the expected file and potentially the intended workflow for finding the flag offset.

    Tried: Run bash ltdis.sh without making it executable first.

    If you try ./ltdis.sh static instead of bash ltdis.sh static, the shell returns a permission denied error because the downloaded script does not have the execute bit set. The fix is either bash ltdis.sh static (which invokes bash directly) or chmod +x ltdis.sh && ./ltdis.sh static. The challenge download does not preserve the executable bit.

    Learn more

    The strings utility scans any binary file and extracts sequences of printable ASCII characters above a minimum length (default 4). This works because compiled programs often contain embedded text: error messages, URLs, version strings, author credits, and - in CTFs - flags. Even without source code, strings is one of the first tools any reverse engineer runs on an unknown binary.

    Shell scripts as wrappers: ltdis.sh is a bash script that wraps strings with specific options and redirects output to a predictably named file. Writing wrapper scripts around existing tools is a common Unix practice - it standardizes arguments, captures output for later analysis, and makes workflows repeatable. The name "ltdis" likely stands for "light disassembly" or similar.

    Static vs. dynamic analysis: The challenge title "Static Ain't Always Noise" plays on two meanings of "static." In reverse engineering, static analysis means examining a binary without executing it - reading its bytes, running strings, disassembling with objdump, or decompiling with Ghidra. Dynamic analysis means running the program and observing its behavior. Both are complementary and important skills.

  2. Step 2
    Search for the flag
    Observation
    I noticed that ltdis.sh saves the extracted strings to a text file named static.ltdis.strings.txt, which contains thousands of lines, so grepping for the picoCTF{ prefix was the fastest way to isolate the flag from all the surrounding binary metadata.
    Grep the output file for the picoCTF prefix. If nothing matches, lower the strings minimum length (default is 4) - the flag may be a short word in a longer transformation. Filter to lines starting with picoCTF{ if multiple matches appear.
    bash
    grep '^picoCTF{' static.ltdis.strings.txt
    bash
    # If no matches, re-run strings with a smaller minimum length:
    bash
    strings -n 3 static | grep -i pico
    What didn't work first

    Tried: Grep the binary file directly instead of the generated text file.

    Running grep 'picoCTF' static on the raw binary produces garbled output because grep processes binary data byte-by-byte without the length-filtering and offset alignment that strings provides. The flag bytes are present in the file but surrounded by null bytes and non-printable characters, so the match either does not display cleanly or triggers grep's 'binary file matches' message with no text shown. Always grep the strings output file, not the binary itself.

    Tried: Search for 'pico' case-sensitively and miss the flag.

    The flag prefix 'picoCTF{' contains a capital C and T, so grep 'pico' static.ltdis.strings.txt matches correctly - but grep 'PICO' or grep 'PicoCTF' would not. More commonly, solvers anchor with ^pico and miss the flag because the strings output includes an offset column at the start of each line (e.g. 1234 picoCTF{...}), so the line does not start with 'pico'. Use grep 'picoCTF' without the caret anchor, or strip the offset column first.

    Learn more

    grep (Global Regular Expression Print) searches text for lines matching a pattern. It's an indispensable Unix tool for filtering large outputs. In CTF work, grepping for known patterns like picoCTF, flag, or FLAG quickly filters thousands of lines of binary output down to the one line you care about.

    A compiled binary can easily contain thousands of strings - library function names, debug symbols, format strings, linker metadata, and more. Without grep, manually scanning static.ltdis.strings.txt would take minutes. With it, the search takes milliseconds. Useful grep flags for CTF work:

    • -i - case-insensitive search (matches picoctf, PICOCTF, etc.)
    • -n - show line numbers so you can find context in the file
    • -A 2 -B 2 - show 2 lines of context around each match
    • -r - recurse into directories (useful when output is split across files)

    Why flags appear in binaries: Flag-checking programs typically compare user input against a stored value. The simplest approach stores the flag as a literal string, making it trivially extractable with strings. More sophisticated challenges encode, encrypt, or generate the flag at runtime to prevent this - but even then, static analysis often reveals key clues.

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.
  • File Magic IdentifierIdentify file types from magic numbers. Paste hex bytes or drop a file to detect PNG, JPEG, ZIP, PDF, ELF, PCAP, SQLite, and dozens of other formats.
  • 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{d15a5m_t34s3r_...}

ltdis.sh runs strings on the binary and saves output; the flag is embedded as a plaintext string.

Key takeaway

Compiled binaries routinely contain embedded plaintext: error messages, version strings, hard-coded credentials, and flags stored for comparison. The strings utility extracts these sequences without executing the program, making it the standard first step in static binary analysis. More sophisticated binaries encode or encrypt secrets at compile time, but strings combined with grep still surfaces surrounding context and metadata that guides deeper analysis with tools like Ghidra or objdump.

Related reading

Want more picoCTF 2021 writeups?

Useful tools for General Skills

What to try next