出题——这关难不倒你算炸单
前言
这次出题采取任意文件读取漏洞 + Laravel 框架结合版,算是基于任意文件读取的最后一舞
本意让选手学会在不同复杂的场景下,利用任意文件读取漏洞扩大危害
Laravel 框架全球使用占比约 64%,另外两个则是 WordPress(25%)、Symfony(23%)
Symfony 框架国内不用,WordPress 现成的靶机(VulnHub)也都有,所以采用 Laravel 框架出题
信息收集
访问页面

观察 URL 发现该站点采用的路由模式,大概率使用的现成框架

页面没啥功能点可测试,注册一个账号试试

查看 Cookie 发现两个字段,laravel_session 以及 XSRF-TOKEN
直接实锤了使用的 Laravel 框架开发

任意文件读取
/_ignition/execute-solution(filter + 双写绕过)
搜索历史漏洞,找到一个 CVE-2021-3129
参考漏洞复现博客:https://www.cnblogs.com/xiaoyunxiaogang/p/16913350.html

阅读完文章发现次漏洞点是基于报错产生的,博客中的报错是:未指定应用程序的 APP_KEY 加密密钥
所以我们不妨切换下思路,手动构造一个报错看看能否跳转到相似的页面上去
URL 中添加错误路由访问,果然跳转到了相似的页面,接口都是一样的

根据页面回显的接口测试数据构造数据包

viewFile 根据字段名推测是要填入文件名,索性填一个 Laravel 环境配置文件 .env 试试
一般入口文件和 .env 都在根目录下,或者入口文件在 /public/ 中

文件不可读取或不存在,使用双写绕过试试
1 | ....//.env |
这次响应不一样了,说是检测到响应中有敏感内容

既然后端检测文件中的内容,那么肯定是对敏感的关键字进行检测了,如 passwd 之类的
我们这里可以采用 PHP 伪协议 php://filter 对其 Base64 编码输出
1 | php://filter/read=convert.base64-encode/resource=....//.env |
解码拿到 APP_KEY 值
1 | base64:Nxxpbkj/QV1f+5uICIZjdf4rG93Dq7gVQbHNOulFxxQ= |

继续扩大危害,尝试读取数据库配置文件 config/database.php
拿到数据库用户名以及一个假的 flag 值

继续读取其框架的日志文件 storage/logs/laravel.log
解码后发现有一个文件的文件名不对劲

尝试去读取文件源代码回显无权限

越权
Laravel Cookie 伪造
编写脚本生成 admin260117 用户的 Cookie 去访问
1 |
|
得到
1 | laravel_session=eyJpdiI6Ild0Z2pqbG1MTHExTm1VeWZhSTE2M1E9PSIsInZhbHVlIjoidEZadHV6cjZNRXpvMUY5TFhpNFJ1aHcxOXBjN0pHRTh3TFRSQlwvQ283K045aXFhNFlrdUlYT1JwODZUSnV6QUM4QTZweTZkcHJUMDNrRmE1VkdKOUl3PT0iLCJtYWMiOiI4OTRmYzQ1ZmFiODRmYTc1YjgzM2IzOTNhN2YwMGNkMDkxZWJjM2MyMTQ4ZGJlZDk0MGI0M2QxODg2NzBjZjljIn0%3D |
成功拿到文件源代码,发现是 PHP 反序列化

反序列化
POP 链
源代码如下:
1 |
|
分析 POP 链调用过程:
User::__destruct()触发$this->profile->show()- 由于
Profile类没有show()方法,触发Profile::__call() Profile::__call()将$this->db作为函数调用:$func()- 如果
$this->db是Database对象,将其作为函数调用会触发Database::__invoke() Database::__invoke()执行echo $this->host- 如果
$this->host是Command对象,将其作为字符串输出会触发Command::__toString() Command::__toString()中调用了exec($this->cmd)造成无回显命令执行
exp
1 |
|
最后也是成功 RCE
