PicoGym: Flag Hunters#
At the moment, PicoGym was moved to CyLabAcademy, some links may differ.
This challenge is called “Flag Hunters”, we will analyze a python code, understand some flaws and find a flag in the program connected through netcat nc.
- Difficulty: Easy
- Category: Reverse Engineering
- Language: Python 3.x
Lyrics jump from verses to the refrain kind of like a subroutine call. There’s a hidden refrain this program doesn’t print by default. Can you get it to print it? There might be something in it for you.
Connect to the program with netcat:
$ nc verbal-sleep.picoctf.net 69420
(The connection address and port may differ from yours)
How to Solve#
First, let’s open the source code lyric-reader.py:
import re
import time
# Read in flag from file
flag = open('flag.txt', 'r').read()
secret_intro = \
'''Pico warriors rising, puzzles laid bare,
Solving each challenge with precision and flair.
With unity and skill, flags we deliver,
The ether’s ours to conquer, '''\
+ flag + '\n'
song_flag_hunters = secret_intro +\
'''
[REFRAIN]
We’re flag hunters in the ether, lighting up the grid,
[...]
We’re chasing that victory, and we’ll never quit.
CROWD (Singalong here!);
RETURN
[VERSE1]
Command line wizards, we’re starting it right,
[...]
Flag on the horizon, what challenge is next?
REFRAIN;
Echoes in memory, packets in trace,
[...]
Buried deep in the noise, but we will prevail.
REFRAIN;
Binary sorcerers, let’s tear it apart,
[...]
Patch it up right, and watch the lock release.
REFRAIN;
Ciphertext tumbling, breaking the spin,
[...]
Decrypt that flag and hear the ether call.
REFRAIN;
SQL injection, XSS flow,
[...]
In the world wide labyrinth, we’re never lost.
REFRAIN;
Stack's overflowing, breaking the chain,
[...]
Control the instruction, flags call my name.
REFRAIN;
END;
'''
MAX_LINES = 100
def reader(song, startLabel):
lip = 0
start = 0
refrain = 0
refrain_return = 0
finished = False
# Get list of lyric lines
song_lines = song.splitlines()
# Find startLabel, refrain and refrain return
for i in range(0, len(song_lines)):
if song_lines[i] == startLabel:
start = i + 1
elif song_lines[i] == '[REFRAIN]':
refrain = i + 1
elif song_lines[i] == 'RETURN':
refrain_return = i
# Print lyrics
line_count = 0
lip = start
while not finished and line_count < MAX_LINES:
line_count += 1
for line in song_lines[lip].split(';'):
if line == '' and song_lines[lip] != '':
continue
if line == 'REFRAIN':
song_lines[refrain_return] = 'RETURN ' + str(lip + 1)
lip = refrain
elif re.match(r"CROWD.*", line):
crowd = input('Crowd: ')
song_lines[lip] = 'Crowd: ' + crowd
lip += 1
elif re.match(r"RETURN [0-9]+", line):
lip = int(line.split()[1])
elif line == 'END':
finished = True
else:
print(line, flush=True)
time.sleep(0.5)
lip += 1
reader(song_flag_hunters, '[VERSE1]')It seems to be a song reading line by line. They limit the number of lines to be sang with:
MAX_LINES = 100So after 100 lines the program halts, to be sure not falling into an infinite loop inside the while.
Inside it, it splits the if checks with the char “;” (semicolon), the possible matches are:
- ‘REFRAIN’: Return to the start of a section of the lyrics
- ‘CROWD’: Check for input of the user.
- Usually we can find a vulnerability in Python 2, where the input can read a variable, but this is not the case, we are dealing with python 3.
- ‘RETURN [number]’: Return to a specific line
- ‘END’: Stop the singing/lyrics/lines. Also stops the program.
And in the start of the program, we have:
# Read in flag from file
flag = open('flag.txt', 'r').read()
secret_intro = \
'''Pico warriors rising, puzzles laid bare,
Solving each challenge with precision and flair.
With unity and skill, flags we deliver,
The ether’s ours to conquer, '''\
+ flag + '\n'
song_flag_hunters = secret_intro +\Where:
flag = open('flag.txt', 'r').read(): Reads the flag.txt file, where our goal residessecret_intro: Is a lyrics section where the flag is stored, but not acessiblesong_flag_hunters: Is the lyrics the user sees, but with thesecret_introappended to the string.
So our string have the flag, but not accessible to the user.
If we insert the input at “CROWD” section ;END;, the program will interpret the “;” as a new line, and also will reproduce the “END” string as a command.
This will result in the program being halted, ending the execution.
So, maybe we can use that as well with the command RETURN [0-9], to return to a specific line in the lyrics. Let’s return to the line ‘1’, I will use echo to append the string to the nc connection:
echo ";RETURN 1;" | nc verbal-sleep.picoctf.net 69420With that, the lyrics return to our secret_intro part, revealing the flag.
Answer: Flag
picoCTF{70637h3r_f0r3v3r_befbccb7}