Points: 100 Category: Miscellaneous Author: sheidan

Introduction

We have access to a restricted Python shell and need to increase our access to the system. To solve the challenge, we must find the flag which is located in the get_flag() function and bypass some filters.

This type of challenge is useful to learn how python introspection works. If you are unfamiliar with Python introspection, you should start by reading this article and this part of Python documentation.

Restriction

After some investigation and testing we are in the following configuration:

  • filtered words: __ (double underscore), __class__, __base__, __subclasses__, _module, open, eval, execfile, exec, type, lambda, getattr, setattr, file, reload, compile, builtins, os, sys, system, vars, getattr, setattr, delattr, input, raw_input, help, open, memoryview, eval, exec, execfile, super, file, reload, repr, staticmethod, property, intern, coerce, buffer, apply ;
  • We can not import anything. We use builtin methods.
  • Any character that matches the [a-zA-Z0-9_-] regexp is invalid in the get_flag() function

Introspection based on func_globals

In order to increase our access, we find which variables contain the blacklist. We use func_globals variable which is a member of any code object to find them. This variable return a dictionary of global variables and their values.

>>> get_flag.func_globals.keys()
['PseudoFile', 'code', 'bad', '__builtins__', '__file__', 'execfile',
'__package__', 'sys', 'getattr', 'Shell', 'banned', 'InteractiveConsole',
'eval', 'get_flag', '__name__', 'main', '__doc__', 'print_function']
>>> get_flag.func_globals["banned"]
['vars', 'getattr', 'setattr', 'delattr', 'input', 'raw_input', 'help',
'open', 'memoryview', 'eval', 'exec', 'execfile', 'super', 'file',
'reload', 'repr', 'staticmethod', 'property', 'intern', 'coerce', 'buffer',
'apply']
>>> get_flag.func_globals["bad"]
['__class__', '__base__', '__subclasses__', '_module', 'open', 'eval',
'execfile', 'exec', 'type', 'lambda', 'getattr', 'setattr', '__', 'file',
'reload', 'compile', 'builtins', 'os', 'sys', 'system', 'vars', 'getattr',
'setattr', 'delattr', 'input', 'raw_input', 'help', 'open', 'memoryview',
'eval', 'exec', 'execfile', 'super', 'file', 'reload', 'repr',
'staticmethod', 'property', 'intern', 'coerce', 'buffer', 'apply']

The keys “banned” and “bad” are interesting because they contain the filtered words. We reset them to nothing:

>>> get_flag.func_globals["banned"] = []
>>> get_flag.func_globals["bad"] = []

Now, we can open the script and display the source code:

>>> fd = open("/home/app/problem.py")
>>> data = fd.read()
>>> fd.close()
>>> print(data)

[SOURCE CODE]

Retrieve the flag

In the source code, we find the get_flag function and the print function that display the flag:

def get_flag(input):
...
    if(eval(input) == super_secret_string):
        print(`'%\xcb'`[{}<[]::~(~({}<[])<<({}<[])[...]

Flag is obfuscated, but if we copy/paste this print command in a Python2 shell, we obtain: tjctf{wh0_kn3w_pyth0n_w4s_s0_sl1pp3ry}.


Pwntera

Yet another french CTF team that sux !