[CVE-2021-27112]LightCMS RCE漏洞复现

前言

这是一次很水的代码审计

漏洞概述

Jianhua Sun LightCMS是 Jianhua Sun开源的一个应用软件。提供一个轻量级的CMS系统,也可以作为一个通用的后台管理框架使用。 LightCMS v1.3.5版本存在安全漏洞,该漏洞源于app Http控制器Admin NEditorController.php中存在远程代码执行漏洞。

环境搭建

项目地址:LightCMS

LightCMS基于Laravel二次开发,所以启动方法也差不多,具体的搭建过程直接参考仓库说明即可。

注意

1、安装组件时如果无法生成vendor目录可以运行composer install --ignore-platform-reqs命令

2、启动服务时Illuminate\Database\QueryException报错可能是因为没有安装php-mysql依赖,参考文章安装(具体看报错信息找解决方案)

3、满足数据库要求:修改.env文件数据库用户密码 或 mysql新建需要的用户:

1
2
3
4
CREATE DATABASE homestead;
CREATE USER 'homestead'@'localhost' IDENTIFIED BY 'secret';
GRANT ALL PRIVILEGES ON *.* TO 'homestead'@'localhost';
FLUSH PRIVILEGES;

4、修改.env文件中的APP_URL选项,改为访问地址

最后,由于只是本地复现,执行php artisan serve 在8000端口开个服务就行了。

漏洞复现

使用admin/admin登录管理员

访问http://IP/admin/neditor/serve/catchimage,POST传file=file:///etc/passwd,此时会返回

1
{"list":[{"url":"http:\/\/IP\/upload\/image\/202104\/0f1726ba83325848d47e216b29d5ab99.jpg","source":"file:\/\/\/etc\/passwd","state":"SUCCESS"}]}

直接访问链接地址即可。

除此之外,还可以直接传php文件RCE。

漏洞分析

catchImage类在框架中只是定义并没有被调用,但由于是admin的功能,所以依然需要进入管理员后台才能利用漏洞。

App\Http\Controllers\Admin\NEditorController::catchImage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public function catchImage(Request $request)
{
    ...
    $files = (array) $request->post('file');
    $urls = [];
    foreach ($files as $v) {
        $extention = pathinfo(parse_url($v, PHP_URL_PATH), PATHINFO_EXTENSION);
        $path = date('Ym') . '/' . md5($v) . '.' . ($extention == '' ? 'jpg' : $extention);
        Storage::disk(config('light.neditor.disk'))
            ->put($path, file_get_contents($v));
        $urls[] = [
            'url' => Storage::disk(config('light.neditor.disk'))->url($path),
            'source' => $v,
            'state' => 'SUCCESS'
        ];
    }

    return [
        'list' => $urls
    ];
}

可以看到这里使用了敏感函数file_get_contents且没有任何过滤,读取文件后就直接保存文件

修复方案

作者的commit记录:

App\Http\Controllers\Admin\NEditorController::fetchImageFile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 非URL格式的文件无法上传
if (!filter_var($url, FILTER_VALIDATE_URL)) {
    return false;
}
...
// 指向链接内容为空的无法上传
$data = curl_exec($ch);
curl_close($ch);
if (!$data) {
    return false;
}

能上传的只有 webp格式 和 正常的图片格式,且需要通过URL链接传入:

App\Http\Controllers\Admin\NEditorController::fetchImageFile

1
2
3
4
5
6
if (isWebp($data)) {
    $image = Image::make(imagecreatefromwebp($url)); // webp格式转化
    $extension = 'webp';
} else {
    $image = Image::make($data); // 图片数据转化
}

App\functions--isWebp

1
2
3
4
5
6
7
8
function isWebp($data)
{
    if (strncmp(substr($data, 8, 7), "WEBPVP8", 7) === 0) {
        return true;
    }

    return false;
}

乍一看只要在文件前添加WWWWWWWWWEBPVP8就可以绕过,不过也确实是这样,但是判断字符之后会调用Image::make(imagecreatefromwebp($url));转化webp图片,不符合格式的无法通过,报错imagecreatefromwebp(): gd-webp cannot get webp info

看起来好像修的差不多了,图像数据处理的代码部分不知道有没有问题,看也看不懂

总结

第一次自己独立审才发现这玩意的难,以前跟着其他师傅的文章一步步走虽然也难,但是有思路,可以知道下一步干啥,相当于开了一个BUFF。独立审直接DEBUFF,效率-99%,果然这条路要一步步走,还是先打磨一段时间吧

参考

LightCMS 安全漏洞

https://github.com/eddy8/LightCMS/issues/19