CTFshow PWN 059 详解:64 位架构下的 Ret2Shellcode 进阶与指令集适配
在上一关 pwn 058 中,我们通过 32 位的 call eax 成功在可执行栈上起舞。今天我们要面对的是它的 64 位进阶版 —— pwn 059。题目依然标榜着:"64 位 无限制"。
从 32 位跨越到 64 位,绝对不是简单的寄存器改个名字(r 开头)那么简单。地址空间的扩大、传参约定的改变以及对指令对齐的要求,都让这次的'无限制'挑战增加了一丝硬核的味道。
第一部分:题目信息与环境侦察
1. 检查保护机制 (checksec)
~/Desktop .............................................................. at 16:20:10 > checksec pwn
[*] '/home/shining/Desktop/pwn'
Arch: amd64-64-little <-- 核心差异:64 位架构
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing <-- 栈可执行 (RWX)
PIE: No PIE (0x400000)
Stack: Executable <-- 权限确认为 RWX
RWX: Has RWX segments
Stripped: No
深度原理分析: 依然是熟悉的 GNU_STACK missing。在 64 位环境下,这种配置同样意味着栈上没有任何执行限制。
- 64 位地址宽度:相比 32 位的 4 字节地址,64 位地址宽度达到了 8 字节,虽然寻址空间巨大,但这也意味着我们在构造 ROP 或填充时需要更精准的字节对齐。
- NX Missing:只要我们能把 RIP 指令指针引导到我们的缓冲区,程序就会像脱缰的野马一样开始解析执行我们的恶意 64 位机器码。
第二部分:破局思路与静态分析
在 64 位下,反编译器(F5)有时会因为复杂的栈平衡调整而报错。
1. 诡异的报错:Decompilation failure
当你尝试在 IDA 中按下 F5 时,可能会弹出:4006F9: call analysis failed
技术解毒:这不是你的 IDA 坏了,而是出题人故意使用了'寄存器间接调用'(Indirect Call)。由于 call rdx 在静态分析时无法确定 rdx 到底指向哪,IDA 的 F5 插件无法构建完整的控制流图,因此罢工。这时候,我们必须回归最原始的武器:阅读汇编。
2. 追踪漏洞点:ctfshow 函数
观察 ctfshow 的汇编实现:
.text:00000000004005BF mov [rbp+s], rdi ; 接收来自 main 的缓冲区地址
.text:00000000004005C3 mov rax, [rbp+s]
.text:00000000004005C7 mov rdi, rax ; 将地址传给 rdi 作为 gets 的参数
.text:00000000004005CF call _gets ; 【核心漏洞】无限制读取输入
.text:00000000004005D4 mov rax, [rbp+s]
.text:00000000004005D8 mov rdi, rax ; 传回给 puts 打印出来
.text:00000000004005DB call _puts
3. 致命一击:main 函数的执行流劫持
回到 main 函数,观察程序在调用 ctfshow 后的动作:
.text:00000000004006DE lea rax, [rbp+var_A0] ; 1. 计算栈上缓冲区 var_A0 的首地址
.text:00000000004006E5 mov rdi, rax ; 2. 作为参数传入 ctfshow
.text:00000000004006E8 call ctfshow ; 3. 调用 gets 往该地址填充数据
.text:00000000004006ED lea rdx, [rbp+var_A0] ; 4. 重新将同一块地址加载到 rdx
.text:00000000004006F4 mov eax, 0
.text:00000000004006F9 call rdx ; 5. 【绝杀】直接跳转到 rdx 执行!


