1. 题目背景与挑战解析
这道来自N1CTF 2026的PWN题"Old_5he1lc0de"是一个典型的shellcode限制挑战。题目通过两个关键文件构建了独特的解题环境:
-
chal.py:作为交互入口,实现了三重防御机制:
- 字节黑名单(ByteCodeAlreadyUsed):禁止重复使用相同字节
- 字节类型限制(ByteCodeTypesOverLimited):总字节类型不超过16种
- 结果验证(FlagNotFound):要求输出必须包含flag内容
-
chal:ELF二进制程序,核心逻辑是:
- 通过mmap分配可执行内存区域(0x8000大小)
- 使用read读取用户输入到该区域
- 清空寄存器后跳转到用户输入位置执行
关键限制:需要分两次提交shellcode,且两次使用的字节类型总数≤16,每次shellcode必须能独立输出flag内容。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 逆向分析与突破口定位
2.1 二进制程序行为验证
使用GDB调试chal程序时,在read返回后的关键寄存器状态:
code复制RAX: 0x0
RDX: 0x7ffff7ff7000 --> 用户输入起始地址
RIP: 0x5555555552a1 <main+165>
程序最终通过jmp rdx跳转到用户输入位置,且注意到:
- RDX是唯一未被清零的寄存器
- 内存页具有RWX权限(通过mmap的prot=7参数设置)
2.2 字节限制的数学约束
假设常规shellcode需要N个不同字节,则:
- 第一次提交消耗N个字节类型
- 第二次提交最多使用(16-N)个新字节类型
- 两次shellcode必须使用完全不同的字节集
通过objdump -d chal分析,发现程序本身已使用约120种不同字节,这意味着无法直接复用程序已有的字节。
3. 多阶段Shellcode构造技术
3.1 第一阶段:RDX指针绘画法
核心思路:利用未被清零的RDX作为"画笔",通过算术指令动态构造真实shellcode。
技术实现:
- 初始化阶段:
nasm复制add dx, 0xe ; 操作码: 66 83 c2 0e
