我在64位Linux上使用Python 2.7。我有以下Python脚本,应该执行一个简单的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()
如果我运行python Scriptname.py
,我会收到内存访问错误。这里的任何人都知道为什么我的脚本不起作用?
编辑: 原始ASM代码:
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
答案 0 :(得分:1)
您将需要python代码,使您的shellcode在具有读/写/执行权限的内存位置运行。因为它运行的shell代码所在的内存不在可执行内存中。您可以创建一个为您执行此操作的函数(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)()
代码应该与Python2.7 +和Python3一起使用
即使您将shell代码字符串插入上面测试程序中的字节对象,它也会失败。你的shell代码字符串似乎缺少字符串本身(hello
);似乎没有正确编码,你依赖于text
标签的静态内存位置。您将需要一个与位置无关的地址。
要修复代码以使其与位置无关,您可以使用RIP相对寻址。将字符串放在代码部分后面的.text
内,完全忘记.data
。此版本应该足够(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
使用OBJDUMP将shell代码程序转换为shell代码字符串可能会有问题。我写了一篇Stackoverflow Answer讨论了OBJDUMP方法的一些缺陷。如果要创建一个可执行文件来独立测试shell代码,那么最好将它组装并链接到可执行文件;使用OBJCOPY将可执行文件转换为二进制文件,然后使用某些东西(如HEXDUMP)将二进制文件转换为shell代码字符串。以下命令应该有效:
nasm -f elf64 shellcode.asm -o shellcode.o
ld shellcode.o -o shellcode
objcopy -O binary shellcode shellcode.bin
如果您运行独立二进制文件shellcode
,则应输出:
您好
然后,您可以使用以下内容将shellcode.bin
转换为shell代码字符串
hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin
输出看起来像:
\ 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
然后,您可以在上面的python程序中插入此shell代码字符串(testshellcode.py
),将 shell代码字符串替换为上面的字符串。您可以使用以下命令运行上面的脚本:
python testshellcode.py
输出应为:
您好
这是更高级的,并且有一些shell代码教程可以解释许多避免字符串中\x00
个字节的技巧。
通常使用shell代码,您希望消除实际字符串漏洞的NUL(\x00
)字节。执行此操作的shellcode.asm
版本可能类似于:
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
如果使用前面提到的命令创建shell代码字符串,HEXDUMP应该生成如下内容:
\ XEB \ X06 \ X48 \ X65 \ X6C \ X6C \ x6f \ X0A \ X31 \ XC0 \ XFF \ XC0 \ X89 \ xc7 \ X48 \ x8d \ X35 \固定的\ XFF \ XFF \ XFF \ X31 \ XD2 \ XB2 \ X06 \ X0F \ X05 \ X31 \ XC0 \ XB0 \ X3C \ X31 \ XFF \ X0F \ X05
此版本与您的代码完全相同,但请注意字符串中没有\x00
个字节。运行时,它也应该打印:
您好