整理文件的时候发现自己还写过这个比赛的 WP,大部分是水题就不搬了,留一道有意思的题记录一下吧。
题目有点久远了,具体内容也忘得差不多了,也没有配套的图片,就将就着看吧(
在首页点击帮助,发现 url 里有 file 参数,我记得是包含了一个 txt 文件。
于是可以用 php 伪协议读取源码(列出关键部分):
1 |
|
可以看到 session 是可控的,可以考虑包含 session 来实现 getshell。
如果自定义的话,php 的 session 文件的保存路径可以在 phpinfo 的 session.save_path 看到。
常见的存放位置(路径 + 文件名):
/var/lib/php/sess_PHPSESSID
/var/lib/php/sessions/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID
而 PHPSESSID
在发送的请求的 cookie 字段中可以看到。
回到本题,虽然 username 看似被 BASE64 编码了,但是可以通过 php 伪协议来获取解码后的数据,现在唯一问题是如何解决 session 文件格式导致的解码失败问题。
我们先来了解一下 BASE64 编码格式,从一个字符串到 BASE64 编码需要这么几步(以 ab
为例):
- 转成 ascii 码:97 98
- 转成对应 8 位二进制:01100001 01100010
- 每组 6 位重分组:011000 010110 0010
- 分组长度不够末尾补零:011000 010110 001000
- 每组对应转为十进制:24 22 8
- 查表得:
YWI
- 末尾补零结尾填充
=
:YWI=
最后一个 6 位的 BASE64 字节块补四位零,最后附加上两个等号;补两位零,最后附加一个等号。
然后参考 session 文件格式,可以得知 session 文件内容一定形如 username|s:<BASE64字串长度>:"<BASE64字串>"
,想办法将 username|s:<BASE64字串长度>:"
填充为正好能被完全分组的形式。
设 BASE64 字串长度的位数为 ,解码时 满足 ,取 ,即 BASE64 字串的长度大于 100。
由 BASE64 编码的特点,密文和原文的长度比约为 4/3,取 payload "a" * 60 + "<?php eval($_POST['cmd']) ?>"
即可满足,此时密文长度为 120。
通过 ?name=
写入 session 文件,用 ?file=
文件包含,然后蚁剑用密码 cmd
连接即可 getshell。