DavidBuchanan314 / unsafe-python

A library to assist writing memory-unsafe code in "pure" python, without any imports (i.e. no ctypes etc.)
MIT License
217 stars 6 forks source link

unsafe-python

A library to assist writing memory-unsafe code in "pure" python, without any imports (i.e. no ctypes etc.)

Supports CPython 3.11 and below (3.12 support coming soon?)

Note: This is a toy. You probably shouldn't use it for anything serious (or anything at all, really).

Core features:

A trivial example, showing how to dereference a null pointer in pure python. The future is now!

>>> import unsafe  # (If "no imports" is a requirement, then you can just copy-paste the code)
>>> mem = unsafe.getmem()
>>> mem[0]
Segmentation fault (core dumped)

For a less trivial example, check out shellcode_example_nocheats.py, which uses ROP to mprotect a shellcode buffer, and then jump into it.

Why?

I don't know.

How?

The CPython bytecode interpreter has documented memory-unsafety bug/features. Notably, the LOAD_CONST opcode (used to load a constant from the co_consts tuple) does not have any bounds checks, presumably for performance reasons. This has been used in the past to execute arbitrary code and escape sandboxes. Until now, these exploits have relied on custom bytecode generation, which is inherently fragile because the bytecode specification changes between different versions and/or implementations of python.

This project uses CPython's code object introspection APIs, along with a heap grooming technique, in order to craft "vulnerable" code objects using CPython's own bytecode compiler. This technique allows us to craft fake python objects on the heap, similar to the "fakeobj()" primitive you might see in exploits for JavaScript engines. For example, we can craft a bytearray with a base address of 0 and a length of SSIZE_MAX, giving us read and write access to raw memory.

TODO:

See Also:

An incomplete list of known CPython memory safety issues: