红帽杯Ezlight复现

预计阅读时间: 2 分钟

红帽杯Ezlight复现

​ 首先给了源码,打开后发现是LightCMS。找到出题人发的issue,很明显我们要调用这个函数,利用Phar反序列化。

​ 在源码里搜Image::make,定位到app/Http/Controllers/Admin/NEditorController.php

image-20210515145245399

​ 同时发现$data来自上面curl的返回结果

image-20210515145425445

​ 查找调用,发现在同文件的catchImage方法中有调用,同时从获取了post('file')的值带入到上面的curl中。

image-20210515145824292

​ 查找该文件调用的路由,发现在/routes/admin.php中,存在post路由

image-20210515150047206

​ 自此找到了到image::make的调用链。然后我们分析Image::make找phar的触发点。首先跟进make方法,发现Image extended Facade。在上面注释中找到\Intervention\Image\Image类。跟进去看,发现要触发__call方法。到这里我就没有思路了,然后去百度了一下,发现官网上写的不是\Intervention\Image\Image类的make方法,而是Intervention\Image\ImageManager 类的make方法(如图)

image-20210515151814247

​ 于是跟进这个方法,发现调用了$this->createDriver()->init($data);根据配置文件,本系统默认使用的是GD拓展来处理图像,所以这个createDriver()应该是返回一个GD的driver,所以直接看init。跟进去,发现调用了$this->decoder->init($data);,接着跟进去,就到了一个根据$data的类型分类处理的结构。

public function init($data)
    {
        $this->data = $data;

        switch (true) {

            case $this->isGdResource():
                return $this->initFromGdResource($this->data);

            case $this->isImagick():
                return $this->initFromImagick($this->data);

            case $this->isInterventionImage():
                return $this->initFromInterventionImage($this->data);

            case $this->isSplFileInfo():
                return $this->initFromPath($this->data->getRealPath());

            case $this->isBinary():
                return $this->initFromBinary($this->data);

            case $this->isUrl():
                return $this->initFromUrl($this->data);

            case $this->isStream():
                return $this->initFromStream($this->data);

            case $this->isDataUrl():
                return $this->initFromBinary($this->decodeDataUrl($this->data));

            case $this->isFilePath():
                return $this->initFromPath($this->data);

            // isBase64 has to be after isFilePath to prevent false positives
            case $this->isBase64():
                return $this->initFromBinary(base64_decode($this->data));

            default:
                throw new NotReadableException("Image source not readable");
        }
    }

​ 其中一个个翻了之后,发现在url的处理过程中,调用了file_get_contents,可以触发phar反序列化(也是本文利用的点);其次在FilePath中调用了isfile,也可以触发反序列化。但是,如果想要触发,需要我们传入的$data前缀为phar://。根据程序中的处理结构,拥有这个前缀,会在$this->isUrl()中返回True,直接进入url的处理过程,所以只能在这里利用。

​ 至此,触发phar的链子分析完了。那么问题就回到了如何传入参数。首先我们上面找到过,触发Image::make的时候,传入了一个file参数,然后通过curl来获取一个结果传入后面的过程。那么,我们让他请求我们的服务器,返回phar://xxxxx。我们还需要在服务器上引入我们的phar文件。这个CMS在上传方面过滤并不严格,只要加上GIF89a的文件头就能上传gif后缀的文件。我找到的上传地点为后台的文章管理处,直接上传文件它会自动帮你重命名,还会“友好地”帮你返回文件地址。

​ 这样我们的反序列化触发点已经齐了,首先用admin/admin进入后台,上传phar文件;然后用接口传入我们的服务器地址,让他请求后返回phar://./upload/xxxxxxxxx,触发链子。(关于反序列化链条本文不再分析,可自行百度或直接用原作者wp中的链子。)

但是这里有一个坑。动调一下,或者把data变量输出到文件,会发现如果直接访问一个静态文件(apache2.4.18+Ubuntu18.04),它返回的内容不只有文件内容,还会多一个\n。我当时测试了一下(可能不对,记不太清了),用php echo也会有这种情况。最后使用print发现解决了问题,返回值不再多一个\n。

Reference:

Intervention Image - Make

GitHub - eddy8/LightCMS: LightCMS是一个基于Laravel开发的轻量级CMS系统,也可以作为一个通用的后台管理框架使用。

RCE vulnerability in lightcms v1.3.7 · Issue #21 · eddy8/LightCMS · GitHub

My-CTF-Challenges/wp.md at main · gml-sec/My-CTF-Challenges · GitHub

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注