【问题标题】:x86_64 Executing Shellcode fails:x86_64 执行 Shellcode 失败:
【发布时间】:2018-06-04 18:00:49
【问题描述】:

我在 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

【问题讨论】:

  • 请完整的错误跟踪
  • You can't just execute arbitrary memory contents as code,或者至少,在没有专门禁用防止这样做的保护的情况下。
  • 我更新了问题。我还更新了 shellcode 并插入了 ASM 代码。我认为它一定可以工作,因为我使用的 python 脚本来自一本名为“grey hat hacking with python”的书
  • 这是我用来将程序集 doe 转换为 shellcode 的方式:命令 1:objdump -d helloWorld 命令 2:objdump -d ./helloWorld|grep '[0-9a-f]: '|grep -v '文件'|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'
  • 我在这个网站上找到了将程序集转换为 shellcode 的命令:commandlinefu.com/commands/view/6051/…

标签: python linux assembly x86-64 shellcode


【解决方案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);似乎没有正确编码,您依赖于textlabel 的静态内存位置。您将需要一个与位置无关的地址。

要修复代码使其与位置无关,您可以使用 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 程序 (testshellcode.py) 中插入这个 shell 代码字符串,用上面的字符串替换 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\xed\xff\xff\xff\x31\xd2\ xb2\x06\x0f\x05\x31\xc0\xb0\x3c\x31\xff\x0f\x05

此版本与您的代码执行相同的操作,但请注意字符串中没有 \x00 字节。运行时,它也应该打印:

你好

【讨论】:

  • nasm -fbin foo.asm/hexdump foo制作shellcode会更容易吗?你需要 BITS 64 在你的文件顶部,因为我认为 NASM 没有一个命令行选项可以将 64 位模式与输出格式分开设置。
  • @PeterCordes 我们在之前关于类似主题的问答中讨论过这个问题。鉴于开发 shell 代码的人通常希望独立测试他们的代码并从中生成 shell 代码字符串,将其拆分并使用这些命令会生成独立的可执行文件和 shell 代码字符串。我专门这样做是有原因的。如果我只对 shell 代码字符串感兴趣,那么你的方式很好。大多数进行 shell 代码开发的人通常会单独测试以进行调试,然后从中生成 shell 字符串。您的方式意味着您必须以两种不同的方式运行 NASM 来生成两者。
  • 是的,这是有道理的,抱歉我忘记了前面的讨论。有一个从工作测试可执行文件制作 shellcode 的秘诀是很好的。我想主要的区别是如果用户搞砸并在 NASM 源中使用section .data 会发生什么;我认为-fbin 会使其连续(与普通的静态可执行文件不同),objcopy -j.text 会忽略它。
  • syscall 的操作码为 0f。当遇到\x0 时,漏洞利用停止。有什么解决方法吗?
  • @srccode : 基于字符串的攻击在到达 0x00 字节时停止,而不仅仅是单个 nybble(4 位)。
猜你喜欢
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 2019-04-17
  • 1970-01-01
相关资源
最近更新 更多