1

I'm using Python 2.7 on 64-bit Linux. I have the following Python script witch should execute a simple Hello World shellcode.

import urllib2
import ctypes

shellcode = "\xb8\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\xbe\xd8\x00\x60\x00\x00\x00\x00\xba\x0e\x00\x00\x00\x0f\x05\xb8\x3c\x00\x00\x00\xbf\x00\x00\x00\x00\x0f\x05"


#Create buffer in memory
shellcode_buffer = ctypes.create_string_buffer(shellcode, len(shellcode))

#Funktionszeiger
shellcode_func  = ctypes.cast(shellcode_buffer, ctypes.CFUNCTYPE(ctypes.c_void_p))

#Shellcode execute
shellcode_func()

If i run python Scriptname.py I get a memory access error. Anybody here have an idea why my script isn't working?

EDIT: Original ASM Code:

section .data
    text db "Hello",10

section .text
    global _start

_start:
    ;syscall sys_write(1, text, 14)
    mov rax, 1
    mov rdi, 1
    mov rsi, text
    mov rdx, 14
    syscall

    ;syscall sys_exit(0)
    mov rax, 60
    mov rdi, 0
    syscall
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
NewInFireFox
  • 37
  • 1
  • 3
  • Full error trace please – Ofer Sadan Jun 04 '18 at 18:05
  • [You can't just execute arbitrary memory contents as code](https://en.wikipedia.org/wiki/Executable_space_protection), or at least, not without specifically disabling the protection against doing that. – user2357112 Jun 04 '18 at 18:10
  • I updated the Question. I also updated the shellcode and inserted the ASM Code. I think it must be working because the python script i used is from a book called "grey hat hacking with python" – NewInFireFox Jun 04 '18 at 18:38
  • 1
    This is the way i used to convert the assembly doe to a shellcode: command 1: objdump -d helloWorld command 2: objdump -d ./helloWorld|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g' – NewInFireFox Jun 04 '18 at 19:08
  • I found the commands to convert the assembly to a shellcode on this website: https://www.commandlinefu.com/commands/view/6051/get-all-shellcode-on-binary-file-from-objdump – NewInFireFox Jun 04 '18 at 19:11
  • You seem to be creating a string from bytes full of NULLs, which is a recipe for failed shellcode – David Hoelzer Jun 04 '18 at 20:26
  • @DavidHoelzer : If he was doing true shell code that is true, however as it is creating a string in python with NUL bytes will work for what he is doing. Of course for a true shell exploit he'd want to eliminate all the NUL bytes in the shell code. In this case it isn't the problem. Here it is a matter of shell code that relies on a fixed memory address (not RIP relative); shellcode not encoded properly; the string `hello` isn't in the shell code; and you'd have to put the shellcode into an executable page of memory. – Michael Petch Jun 04 '18 at 20:43

1 Answers1

3

You are going to need python code that makes your shellcode run in a memory location that has Read/Write/Execute privileges. As it is the memory your shell code is running from is not in executable memory. You can create a function that does this for you (testshellcode.py):

import ctypes, mmap, sys

# Convert string to bytes object. Differs between Python2 and Python3
if sys.version_info >= (3, 0):
    def b(string, charset='latin-1'):
        if isinstance(string, bytes) and not isinstance(string, str):
            return (string)
        else:
            return bytes(string, charset)
else:
    def b(string):
        return bytes(string)

def create_shellcode_function (shellcode_str):
    shellcode_bytes = b(shellcode_str)

    # Allocate memory with a RWX private anonymous mmap
    exec_mem = mmap.mmap(-1, len(shellcode_bytes),
                         prot = mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC,
                         flags = mmap.MAP_ANONYMOUS | mmap.MAP_PRIVATE)

    # Copy shellcode from bytes object to executable memory
    exec_mem.write(shellcode_bytes)

    # Cast the memory to a C function object
    ctypes_buffer = ctypes.c_int.from_buffer(exec_mem)
    function = ctypes.CFUNCTYPE( ctypes.c_int64 )(ctypes.addressof(ctypes_buffer))
    function._avoid_gc_for_mmap = exec_mem

    # Return pointer to shell code function in executable memory
    return function

# linux machine code
shellcode = "shell code string here"

# Create a pointer to our shell code and execute it with no parameters
create_shellcode_function(shellcode)()

The code should work with Python2.7+ and Python3


Even if you insert your shell code string into the byte object in the test program above it will fail. Your shell code strings seem to be lacking the string itself (hello); doesn't seem to be encoded properly and you rely on a static memory location for the textlabel. You will need an address that is position independent.

To fix the code so it is position independent you can use RIP relative addressing. Place the string inside the .text after the code section and forget about .data altogether. This version should suffice (shellcode.asm):

section .text
    global _start

_start:
    ;syscall sys_write(1, text, text_len)
    mov rax, 1
    mov rdi, 1
    lea rsi, [rel text]     ; RIP Relative addressing for Position independent code
    mov rdx, text_len       ; text length computed by assembler
    syscall

    ;syscall sys_exit(0)
    mov rax, 60
    mov rdi, 0
    syscall

    text db "Hello",10
text_len EQU $-text         ; Rather than hard coding length compute text length

Using OBJDUMP to convert a shell code program to a shell code string can be problematic. I wrote a Stackoverflow Answer discussing some of the pitfalls of the OBJDUMP method. If you are creating an executable to test your shell code standalone then it is preferable to assemble and link it to an executable; use OBJCOPY to convert the executable to binary and then use something (like HEXDUMP) to convert the binary to a shell code string. The following commands should work:

nasm -f elf64 shellcode.asm -o shellcode.o 
ld shellcode.o -o shellcode
objcopy -O binary shellcode shellcode.bin

If you run the standalone binary shellcode it should output:

Hello

You can then convert shellcode.bin to a shell code string with:

hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin

The output would look something like:

\xb8\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\x8d\x35\x13\x00\x00\x00\xba\x06\x00\x00\x00\x0f\x05\xb8\x3c\x00\x00\x00\xbf\x00\x00\x00\x00\x0f\x05\x48\x65\x6c\x6c\x6f\x0a

You can then insert this shell code string in the python program above (testshellcode.py) replacing shell code string here with the string above. You can run the script above with:

python testshellcode.py

The output should be:

Hello


This is more advanced, and there are shell code tutorials that explain many of the tricks to avoid \x00 bytes in a string.

Usually with shell code you want to eliminate NUL (\x00) bytes for real string exploits. A version of shellcode.asm that does this could look something like:

section .text
    global _start

_start:
    jmp afterdata
    text db "Hello",10
text_len EQU $-text

afterdata:
    ;syscall sys_write(1, text, text_len)
    xor eax, eax
    inc eax
    mov edi, eax
    lea rsi, [rel text]
    xor edx, edx
    mov dl, text_len
    syscall

    ;syscall sys_exit(0)
    xor eax, eax
    mov al, 60
    xor edi, edi
    syscall

If you create shell code string with the commands mentioned previously, HEXDUMP should produce something like:

\xeb\x06\x48\x65\x6c\x6c\x6f\x0a\x31\xc0\xff\xc0\x89\xc7\x48\x8d\x35\xed\xff\xff\xff\x31\xd2\xb2\x06\x0f\x05\x31\xc0\xb0\x3c\x31\xff\x0f\x05

This version does the same thing as your code but notice there are no \x00 bytes in the string. When run, it too should print:

Hello

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • Would it be easier to make shellcode with `nasm -fbin foo.asm` / `hexdump foo`? You'd need `BITS 64` at the top of your file, because I don't think NASM has a command-line option to set 64-bit mode separately from the output format. – Peter Cordes Jun 05 '18 at 05:41
  • 1
    @PeterCordes We went over this in a previous q/a on similar subject. Given that people who develop shell code usually want to test their code standalone and generate shell code strings from it, splitting it up and using these commands produces both stand alone executable and the shell code string. I specifically do it this way for a reason. If I'm only interested in shell code string then your way is fine. Most people who do shell code development usually test standalone for debugging and then produce the shell string from it. Your way means you have to run NASM two diff ways to produce both. – Michael Petch Jun 05 '18 at 05:45
  • 1
    Yup that makes sense, sorry I forgot the previous discussion. Having a recipe for making shellcode from a working test executable is good. I guess the main difference is what happens if the user screws up and uses a `section .data` in the NASM source; `-fbin` will make it contiguous I think (unlike in a normal static executable), `objcopy -j.text` will leave it out. – Peter Cordes Jun 05 '18 at 05:52
  • ```syscall``` has opcode ```0f```. Exploits stops when it encounters ```\x0```. Is there any workaround for that? – srccode Mar 10 '19 at 19:45
  • 1
    @srccode : String based exploits stop when they reach a byte of 0x00 not just a single nybble (4 bits). – Michael Petch May 07 '19 at 15:59
  • 1
    this answer is gold, thanks @MichaelPetch – CalfCrusher Sep 23 '21 at 13:40