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 text
label. 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