
TPCTF 2025 - where is my rop

very nice apache, love from cgi
本题由我和 dbgbgtf 共同完成
文件属性
属性 | 值 |
---|---|
Arch | amd64 |
RELRO | Full |
Canary | on |
NX | on |
PIE | on |
strip | yes |
解题思路
哪有什么rop,我只看到了命令注入。
分别分析了basement
、login.cgi
、logout.cgi
、gen_enc
,后两者代码很短,
看不出什么明显的漏洞。前三者都使用/tmp/tpctf.sock
这个AF_UNIX
socket来进行进程间通信。
其中basement
中有命令执行,我们可以控制一些参数,但是对大多数符号做了过滤,
几乎没有绕过的方式,并且在login.cgi
中没有明显的控制方式。
然后 dbgbgtf 发现了login.cgi
在处理Authorization
头时,程序校验完base64字符串,
并没有检查其长度。随后程序将Basic
后的信息做base64解码并放到char auth_buf[0x200]
上,
这一块数据位于bss上,并与cmd
相邻。通过写入很长的base64的Authorization,可以覆盖cmd
,
在sendcmd
的时候可以实现发送任意指令。
在容器中调试
本题的环境比较复杂,不方便在本地调试,可以在启动容器后,在其中安装gdbserver, 然后编写一个前置的cgi来代理login,方便在login被拉起的时候用gdb连上去:
1 |
|
在socket中传输的数据大约是按照0x80来切块的,而数据是从Authorization中按:
分割拿到的,
我们可以轻松控制。对于冒号之间字段长度的检验,除了最后一个字段,其他字段均需小于0x80,
亦即最后一个字段可以无限长。
观察命令执行中所禁止的字符,包括\n & $ ; < > ^ |
和`
,
但是空格等字符没有拦截,会不会内置的命令可以利用的呢?使用man
查看ping
,
traceroute
和iperf3
,其中iperf3
的客户端有-T
和--logfile
两个特殊选项,
第一个是在输出的所有行之前添加一个自己的title,第二个是将输出附加到某个文件中。
查看容器中的acme.sh
,其中啥也没干,就很适合用来作为脚本的载体。通过先启动iperf3
服务端,
然后用空格、引号等指导iperf3
客户端向acme.sh
中写入命令,就可以通过任意acme命令触发脚本。
比如说在acme.sh
中写入cp /*flaG* /var/www/html/flag.html
,执行后就可以将flag写入到html目录下,
这样访问/flag.html
就可以拿到flag。
flag的名字是?
赛后交流发现本题出网,因此有的师傅通过iperf3的文件将flag传出去。当然我这个解法不出网,
应该更加符合出题人的想法。只是没想到flag名称相比给的附件变得有点多,
先用find / -maxdepth 1 -fprint /var/www/html/ls.html
列出有哪些文件,通过curl获取:

一开始完全没想到g大写了,有点离谱... 才不是因为没有想到直接/*f*
就行了
最后考虑怎样构造payload:由于我们修改了要执行的cmd
,因此分支会相较我们的原动作有差异。
由于cmd
非LOGIN
和REGISTER
,最终会走 reset_password 的逻辑,
因此在我们的Authorization中需要3个:
才能成功执行sendcmd
。
更多细节
压缩包中还有一些html和js文件,阅读后可以发现,如果在网页端尝试登录,会首先将密码使用gen_enc
加密,再提交登录/注册请求。然而,这并不是强制的。由于没有提供注册接口,数据库又是空的,因此我们需要先手动发送http请求来注册。注册成功后如果登录,由于不存在manager.cgi
,因此会显示404。
EXPLOIT
1 | from pwn import * |
- 标题: TPCTF 2025 - where is my rop
- 作者: RocketDev
- 创建于 : 2025-03-11 10:12:00
- 更新于 : 2025-03-11 10:12:00
- 链接: https://rocketma.dev/2025/03/11/whereIsRop/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。