目标站点是歪歪朋友丢过来的,一个老博客程序,秋蝉后台登录地址直接暴露在页面底部。渗透我扫了目录,测试没有WAF,歪歪PHP版本7.2,秋蝉服务器是渗透台CentOS。这种老站,测试我第一反应就是歪歪看插件和主题的漏洞,别急着猜密码。秋蝉
先看了robots.txt,渗透没东西。测试用wappalyzer识别出用的歪歪是Typecho,版本号没显示。秋蝉Typecho老版本有个经典的渗透install目录重装漏洞,我直接访问了/install.php?step=3,结果跳转到了404。看来不是那个老掉牙的版本。
转念一想,后台登录页有验证码,我懒得爆破。于是抓了个登录包,发现密码字段是明文传输,没有token防CSRF。但这不是重点,重点是响应头里有个X-Powered-By: PHP/7.2.33,这版本在2020年就停止安全维护了,有已知的堆溢出漏洞,但我没那精力搞远程溢出,不现实。
往下翻源码,在/usr/themes/default/footer.php里发现了个自定义函数,调用了file_get_contents去加载远程图片。参数从URL的img变量传进来,没过滤。我试了?img=http://127.0.0.1/flag,页面直接渲染出了内网IP的响应内容——这不就是SSRF嘛。
但SSRF能干嘛?读内网文件得配合协议,试了file:///etc/passwd,被拦截了,估计是禁了file协议。不过能访问内网端口,我用它扫了一下同网段的Redis服务,发现192.168.1.10:6379开着,而且没密码。
这就好办了。SSRF发HTTP请求,但Redis协议是TCP的,HTTP请求没法直接打。我换个思路,用gopher协议试试。大多数PHP环境会禁用gopher,但这个站居然没禁。构造一个gopher请求,往Redis里写crontab计划任务,反弹shell。
细节上有个坑,gopher的URL编码得用两次,不然Redis解析不了。我本地用Python脚本生成payload,把\\r\\n全部编码成%0d%0a,再整体URL编码一次。第一次发过去,没反应,检查发现Redis的dir配置默认在/var/spool/cron,但CentOS的cron目录是/var/spool/cron/,权限对apache用户不可写。我改写了config set dir /var/spool/cron/,然后写入root用户的计划任务,反弹到我的VPS。
等了一分钟,shell来了。是个www-data权限,但cron任务是以root执行的,所以直接拿到root。整个过程没碰任何已知CVE,就是逻辑漏洞组合:SSRF+Redis未授权+PHP配置不当。事后我给朋友修复建议:升级PHP,禁用gopher和file协议,Redis加密码绑定内网IP。老站点的坑,往往不在功能,而在那些没人记得的旁路配置。