A method has been published for bypassing Python’s isolated code execution systems, based on the use of a long-known bug that appeared in Python 2.7, identified in 2012 and still not fixed in Python 3. The bug allows using specially linked Python code to initiate a call to already freed memory (Use-After-Free) in Python. Initially, it was assumed that the error does not pose a security threat and only in very rare cases, usually artificially created, can lead to an abnormal termination of the script.
A security researcher under the pseudonym kn32 became interested in the problem and managed to prepare a working exploit that makes it possible to call any system command without having direct access to methods like os.system . The exploit is implemented in pure Python and works without importing external libraries and without installing the “code.__new__” handler. Of the hooks, only “builtin.__id__” is used, which is usually not forbidden. On the practical side, the proposed code can be used to bypass isolation mechanisms in various services and environments (for example, in learning environments, online shells, built-in handlers, etc.) that allow execution of Python code, but limit available calls and do not allow access methods such as os.system.
The proposed code is an analogue of the os.system call, which works through the exploitation of a vulnerability in CPython. The exploit works with all versions of Python 3 on x86-64 systems and is stable on Ubuntu 22.04 even with PIE, RELRO and CET security modes enabled. The work comes down to getting information about the address of one of the functions from the Python code in executable CPython code. Based on this address, the base address of CPython in memory and the address of the system() function in the loaded libc instance are calculated. At the end, a direct transition to a certain address system is initiated with substitution of the pointer of the first argument to the string “/bin/sh”.