Description
lyric-reader.py prints verses and a refrain but never displays the secret intro that holds the flag. Use the CROWD prompt to inject a `RETURN 0` directive and jump to the hidden lines.
Read the script to understand that CROWD lines accept user input, which is then split on semicolons and interpreted as additional instructions.
Connect to the remote service (or run the script locally) and wait for the first CROWD prompt.
nc verbal-sleep.picoctf.net 56688;RETURN 0Solution
- Step 1Leverage CROWD inputWhen prompted with `Crowd:`, enter a string that includes `;RETURN 0`. Because the interpreter splits on semicolons, the injected `RETURN 0` will set `lip` to 0 (the top of the song).
Learn more
This challenge implements a custom domain-specific language (DSL) - a mini interpreter that processes song lyrics as a script. The interpreter reads lines sequentially, handles special directives like
VERSE,REFRAIN,CROWD, andRETURN, and maintains an instruction pointer (lip) that tracks the current line. This architecture is similar in concept to early programming languages like BASIC, which also used line numbers andGOTOstatements.The vulnerability is command injection through a delimiter. The script trusts user input from
CROWDprompts but then processes it through the same parser as the script itself, splitting on semicolons. By injecting a semicolon followed by a valid directive, the attacker forces the interpreter to execute arbitrary instructions mid-stream. This is conceptually identical to SQL injection (where user input is interpolated into a SQL statement) and shell injection (where user input is passed to a shell that interprets semicolons as command separators).The
RETURN 0directive sets the instruction pointer back to line 0 - the beginning of the file - where the hiddensecret_introsection is defined. Because normal execution never reaches line 0 (it starts after the intro), the flag is never printed under normal circumstances. This "dead code" pattern is sometimes used in CTFs to hide secrets that require control-flow manipulation to reach. - Step 2Reveal the secret introJumping to line 0 prints `secret_intro`, which concatenates the flag. Let the script continue and read the picoCTF string.
Learn more
Arbitrary control flow - the ability to redirect a program's execution pointer to any location - is one of the most powerful primitives in binary exploitation. In this scripted context, it is achieved simply by injecting a
RETURNinstruction. In binary exploitation, equivalent capabilities require stack-based buffer overflows, return-oriented programming (ROP), or use-after-free vulnerabilities to overwrite the instruction pointer.The principle of least privilege suggests that user-provided data should never be treated as code. The fix for this script would be to either sanitize CROWD input (removing semicolons and rejecting directive keywords) or process CROWD input in a completely separate context that cannot influence the interpreter's control flow. This separation between data and code is a fundamental principle in secure programming.
In real-world applications, similar vulnerabilities appear in template injection (user input rendered as a template that executes code), macro injection (user content treated as spreadsheet formulas), and eval-based architectures (user strings passed to eval or exec). All share the same root cause: insufficient separation between data and execution context.
Flag
picoCTF{70637h3r_f0r3v3r_750...}
Any input containing `;RETURN 0` works because the preceding characters are ignored.