Exploiting Self-Modifying Code: Flag Hunters CTF Walkthrough
Challenge Info:
- Platform: picoCTF 2025 - Flag Hunters
- Category: Reverse Engineering
- Difficulty: Easy
- Technique: Command Injection via Self-Modifying Code
Understanding the Challenge
So we get this Python script called lyric-reader.py that's basically a music player for a song called "Flag Hunters." The challenge description drops hints about a "hidden refrain" and "jumping subroutines" - sounds like we need to mess with how the program runs to get to code it normally skips over.
Analyzing the Vulnerable Code
When you dig into the source code, there's this reader function that goes through song lyrics line by line. It keeps track of where it is using a variable called lip (probably short for Line Instruction Pointer).
Here's where things get interesting - check out how it handles the "CROWD" part:
# Inside the reader loop:
elif re.match(r"CROWD.*", line):
crowd = input('Crowd: ')
song_lines[lip] = 'Crowd: ' + crowd # <--- This is the weak spot
lip += 1
The Vulnerabilities
There are actually two problems here:
- First issue: The program just takes whatever you type and writes it directly into the song lyrics stored in memory. Like, it's literally changing itself while it's running.
- Second issue: The program splits lines by semicolons (
;) to look for commands:
for line in song_lines[lip].split(';'): # <--- See the semicolon split?
# ... checks for commands like RETURN or END ...
This means if you sneak a semicolon into your input, everything after it gets treated as a command.

Figure 1: Spotting the weak point in the code.
Planning the Exploit
Looking at the script, the flag is right there at the top (Line 0) in something called secret_intro. But when the program starts, it skips that and jumps straight to .
Exploit Strategy
So our goal is simple: make the program go back to Line 0. Good news - there's already a command for that: RETURN .
Execution Flow
We're going to use that "Crowd" input to inject our own command. Here's the plan:
- Wait for the program to ask for
Crowd:input. - Type this:
any_text;RETURN 0 - What happens:
- Your input gets saved into the song lyrics.
- The song keeps playing normally.
- When it loops back around (after Verse 2), it reads your modified line again.
- This time it sees
RETURN 0and actually runs it as a command. - Boom - jumps to Line 0 and shows the flag.
Step-by-Step Exploitation
Step 1: Connect to the Server
nc saturn.picoctf.net <YOUR_PORT>
Step 2: Inject the Payload
When it asks for Crowd:, type:
w;RETURN 0
Step 3: Wait for Execution
Just wait. Let Verse 2 play out. Your payload is sitting there in memory, ready to go.
Step 4: Flag Capture
Watch it pop. When the Refrain comes back around, your injected command triggers and the flag appears.
Successful Exploitation
Screenshot below shows the whole thing in action.
Flag: picoCTF{mu51c_15_1n_7h3_...}

Figure 2: The payload does its thing - jumps to line 0 and prints the flag.
Key Takeaways
Security Lessons
- Never trust user input that modifies program state
- Self-modifying code creates unpredictable security risks
- Input validation should happen before data storage
- Command separators in user input are dangerous
Attack Techniques
- Command injection via delimiter abuse
- Exploiting self-modifying code patterns
- Program flow redirection attacks