
京麒CTF 2025 - OldWine

感谢 熙熙 师傅提供的思路!
文件属性
属性 | 值 |
---|---|
Arch | amd64 |
RELRO | Full |
Canary | off |
NX | on |
PIE | on |
strip | no |
libc | 2.39-0ubuntu8.4 |
seccomp rules

解题思路
程序禁止了one gadget,可以调整rbp,也可以在栈上向后写。类似的思路其实当时西湖论剑的 babytrace 就出现过,然而一下没想到,没做出来,还在那里找各种gadget,这下吃一堑吃一堑了。
原本的栈大小是0x10,加上[rbp]
和返回地址总共0x20字节,然后索引从rbp - 0x10
开始算。
原始栈布局如下所示:
如果将[rbp]
调整为rbp + 0x10
,那么栈布局就会变为:
为什么要这么做?反汇编read
,如果成功读取,那么有效的指令只有:
1 | cmp byte ptr [rip + __libc_single_threaded], 0 |
因此在call read@plt
时,rsp只扩展了8字节,也就是返回地址。查看上面的栈布局,
不难发现,当call
时,rsp刚好等于rbp - 0x10
,也就是说,我们可以控制参数,
向read
函数的返回地址写入数据。将idx
和size
分别控制为0和一个比较大的值,
由于rsi和rdx没有变化,可以将返回地址劫持到main
函数中mov edi, 1; call write@plt;
的地方,
这样就可以泄露出栈上的数据,找到libc的值。
后面就简单了,打传统rop,走execveat
就可以。
EXPLOIT
1 | from pwn import * |
- 标题: 京麒CTF 2025 - OldWine
- 作者: RocketDev
- 创建于 : 2025-05-28 12:05:00
- 更新于 : 2025-05-28 12:19:00
- 链接: https://rocketma.dev/2025/05/28/OldWine/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论