PicoGym: Flag Hunters#
No momento, o PicoGym foi transferido para o CyLabAcademy. Alguns links podem estar diferentes.
Este desafio se chama “Flag Hunters” e nele analisaremos um código Python, identificaremos algumas falhas e encontraremos uma flag no programa conectado através do netcat nc.
- Dificuldade: Fácil
- Categoria: Engenharia Reversa
- Linguagem: 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
Ou numa tradução livre:
A letra pula dos versos para o refrão como uma chamada de sub-rotinas. Há um refrão oculto que este programa não mostra por padrão. Você consegue fazê-lo imprimir esse refrão? Pode ser que ele seja útil para você.
Conecte-se ao programa com o netcat:
$ nc verbal-sleep.picoctf.net 69420
(O endereço e a porta de conexão podem ser diferentes dos seus)
Como Resolver#
Primeiro, vamos abrir o código-fonte 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]')Parece ser uma canção lida verso por verso. Eles limitam o número de versos a serem cantados com:
MAX_LINES = 100Assim, após 100 linhas, o programa para, para garantir que não entre em um loop infinito dentro do while.
Internamente, ele divide as verificações if com o caractere “;” (ponto e vírgula), sendo as possíveis correspondências:
- ‘REFRAIN’: Retorna ao início de uma seção da letra
- ‘CROWD’: Verifica a entrada do usuário.
- Normalmente, podemos encontrar uma vulnerabilidade no Python 2, onde a entrada pode ler uma variável, mas este não é o caso, pois estamos lidando com o Python 3.
- ‘RETURN [número]’: Retorna a uma linha específica
- ‘END’: Interrompe o canto/letra/verso. Também interrompe o programa.
E no início do programa, temos:
# 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 +\Onde:
flag = open('flag.txt', 'r').read(): Lê o arquivo flag.txt, onde reside nosso objetivo.secret_intro: É um parágrafo onde a flag é armazenada, mas não acessível.song_flag_hunters: São as letras da música que o usuário vê, mas com a variávelsecret_introanexada à string.
Portanto, nossa string contém a flag, mas ela não está acessível ao usuário.
Se inserirmos a entrada na seção “CROWD” o valor ;END;, o programa interpretará o “;” como uma nova linha e também reproduzirá a string “END” como um comando.
Isso fará com que o programa seja interrompido, encerrando sua execução.
Então, talvez possamos usar isso também com o comando RETURN [0-9], para retornar a uma linha específica da letra da música. Vamos tentar retornar à linha ‘1’, vou usar o comando echo para adicionar a string na conexão nc:
echo ";RETURN 1;" | nc verbal-sleep.picoctf.net 69420Com isso, a letra retorna à parte secret_intro, revelando a flag.
Resposta: Flag
picoCTF{70637h3r_f0r3v3r_befbccb7}