Bypass Python sandboxes

These are some tricks to bypass python sandbox protections and execute arbitrary commands.

Command Execution Libraries

The first thing you need to know is if you can directly execute code with some already imported library, or if you could import any of these libraries:

os.system("ls")
os.popen("ls").read()
commands.getstatusoutput("ls") 
commands.getoutput("ls")
commands.getstatus("file/path")
subprocess.call("ls", shell=True)
subprocess.Popen("ls", shell=True)
pty.spawn("ls")
pty.spawn("/bin/bash")
platform.os.system("ls")

#Other interesting functions
open("/etc/passwd").read()
open('/var/www/html/input', 'w').write('123')

Remember that the open and read functions can be useful to read files inside the python sandbox and to write some code that you could execute to bypass the sandbox. Python2 input() function allows to execute python code before the program crashes.

Importing

If sysmodule is present, you can use it to access oslibrary for example:

You can also import libraries and any file is using execfile() (python2):

Python try to load libraries from the current directory first: python3 -c 'import sys; print(sys.path)'

Bypass pickle sandbox with default installed python packages

Default packages

You can find a list of pre-installed packages here: https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html Note that from a pickle you can make the python env import arbitrary libraries installed in the system. For example the following pickle, when loaded, is going to import the pip library to use it:

For more information about how does pickle works check this: https://checkoway.net/musings/pickle/

Pip package

If you have access to pip or to pip.main() you can install an arbitrary package and obtain a reverse shell calling:

You can download the package to create the reverse shell here. Please, note that before using it you should decompress it, change the setup.py, and put your IP for the reverse shell:

This package is called Reverse.However, it was specially crafted so when you exit the reverse shell the rest of the installation will fail, so you won't leave any extra python package installed on the server when you leave.

Executing python code

This is really interesting if some characters are forbidden because you can use the hex/octal/B64 representation to bypass the restriction:

Compiling

In a previous example you can see how to execute any python code using the compile function. This is really interesting because you can execute whole scripts with loops and everything in a one liner (and we could do the same using exec). Anyway, sometimes it could be useful to create a compiled object in a local machine and execute it in the CTF (for example because we don't have the compile function in the CTF).

For example, let's compile and execute manually a function that reads ./poc.py:

If you cannot access eval or exec you could create a proper function, but calling it directly is usually going to fail with: constructor not accessible in restricted mode. So you need a function not in the restricted environment call this function.

Builtins

Builtins functions of python2 Builtins functions of python3

If you can access to the__builtins__ object you can import libraries (notice that you could also use here other string representation showed in last section):

No Builtins

When you don't have __builtins__ you are not going to be able to import anything nor even read or write files. But there is a way to take that functionality back:

Python2

Python3

Python2 and Python3

Finding types

Dissecting functions

In some CTFs you could be provided the name of a custom function where the flag resides and you need to see the internals of the function to extract it.

This is the function to inspect:

dir

globals

__globals__ and func_globals(Same) Obtains the global environment. In the example you can see some imported modules, some global variables and their content declared:

__code__ and func_code: You can access this to obtain some internal data of the function

Disassembly a function

Notice that if you cannot import dis in the python sandbox you can obtain the bytecode of the function (get_flag.func_code.co_code) and disassemble it locally. You won't see the content of the variables being loaded (LOAD_CONST) but you can guess them from (get_flag.func_code.co_consts) because LOAD_CONSTalso tells the offset of the variable being loaded.

References

****

Last updated