Old tricks

My previous article about Google Foobar was written about 10 months ago. Since that time i did not come back to the tasks. Now, when i am back, i grabbed one more task from level 4 and started to solve it. 10 minutes later i totally forgot about coding and started to subvert the sandbox again. The process did amuse me a lot. Let's dive into the details.

In the G's tasks you should implement a function answer(*args) which implements the solution and returns the answer. Wouldn't it would be great to see the inputted arugments? - i thought. In the previous part i wrote how i found how to output args via a specially crafted exception. That bug was fixed. Now custom exceptions are handled correctly, no information is leaked, at least seems like that. What they did: they fixed all exceptions which are raised from within the answer function. However, these exceptions still can be raised from any other place in the program without any sanitization. E.x. from the module itself. What made it even easier to exploit is to raise an exception, which body contained the message you want to see, like this: raise Exception(secret_data).

Outputted current directory

Let's have a bit of fun with that and output something more interesting, e.x. let's traverse the available file system and check the files.

File system

File system turned out to be quite boring as there was the only file /main.py. I used b64 to output the contents in a nice way and not to format the source code myself.

A part of the main.py

I did not find anything too serious in the source code, if you can, let me know :D

New quirks

Another interesting quirk takes into consideration the fact that in the exception output there is a line number where the exception occured. If we can somehow use that number as a side channel, we would come up with an encoding to send the data. The quirk was quickly found:

def f():
    1/0

def fix(c, n):
    return type(c)(c.co_argcount, c.co_nlocals, c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names, c.co_varnames, c.co_filename, c.co_name, n, c.co_lnotab)

f.func_code = fix(f.func_code, 5555)

f()

Example of an exception where we control the outputted line number

From now, it is pretty easy to extract some secret data from the application. Get the data, encode it in an integer, make a specially crafted exception, decode the data back. Though output line number is limited by 2**32, it is now a problem as the process can be iterative.

If you have any interesting python quirks, escapes, which you have implemented, please send me a DM https://twitter.com/easy_pwn