路漫漫其修远兮,吾将上下而求索

0%

fastadmin前台漏洞复现

FastAdmin前台漏洞getshell分析

影响版本

V1.0.0.20200506_beta

分析

文件包含

根据官网的修复方法

image-20200921165512720

可以看到产生漏洞的位置 application/index/controller/User.php 看一下 _empty() 方法,将传入的 $name参数未经过滤,直接传输到 fetch方法中。

先调用了 view文件内的 fetch 方法

1
public function fetch($template = '', $vars = [], $replace = [], $config = [], $renderContent = false)
2
   {
3
       // 模板变量
4
       $vars = array_merge(self::$var, $this->data, $vars);
5
6
       // 页面缓存
7
       ob_start();
8
       ob_implicit_flush(0);
9
10
       // 渲染输出
11
       try {
12
           $method = $renderContent ? 'display' : 'fetch';
13
           // 允许用户自定义模板的字符串替换
14
           $replace = array_merge($this->replace, $replace, (array) $this->engine->config('tpl_replace_string'));
15
           $this->engine->config('tpl_replace_string', $replace);
16
           $this->engine->$method($template, $vars, $config); //$template为传入参数
17
       } catch (\Exception $e) {
18
           ob_end_clean();
19
           throw $e;
20
       }
21
      ...

之后调用了 think文件内的 fetch方法

1
public function fetch($template, $data = [], $config = [])
2
    {
3
        if ('' == pathinfo($template, PATHINFO_EXTENSION)) {
4
            // 获取模板文件名
5
            $template = $this->parseTemplate($template);
6
        }
7
        // 模板不存在 抛出异常
8
        if (!is_file($template)) {
9
            throw new TemplateNotFoundException('template not exists:' . $template, $template);
10
        }
11
        // 记录视图信息
12
        App::$debug && Log::record('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]', 'info');
13
        $this->template->fetch($template, $data, $config);

在此处经过 is_file 函数判断 ,再次调用template文件内的 fetch方法

1
public function fetch($template, $vars = [], $config = [])
2
{
3
    if ($vars) {
4
        $this->data = $vars;
5
    }
6
    if ($config) {
7
        $this->config($config);
8
    }
9
    if (!empty($this->config['cache_id']) && $this->config['display_cache']) {
10
        // 读取渲染缓存
11
        $cacheContent = Cache::get($this->config['cache_id']);
12
        if (false !== $cacheContent) {
13
            echo $cacheContent;
14
            return;
15
        }
16
    }
17
    $template = $this->parseTemplateFile($template);
18
    if ($template) {
19
        $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($this->config['layout_name'] . $template) . '.' . ltrim($this->config['cache_suffix'], '.');
20
        if (!$this->checkCache($cacheFile)) {
21
            // 缓存无效 重新模板编译
22
            $content = file_get_contents($template);
23
            $this->compiler($content, $cacheFile);
24
        }
25
        // 页面缓存
26
        ob_start();
27
        ob_implicit_flush(0);
28
        // 读取编译存储
29
        $this->storage->read($cacheFile, $this->data); //此处为thinkphp<5.0.18 文件包含漏洞发生处
30
        $content = ob_get_clean();
31
        ......

主要意思就是将传入的未经过滤$template文件,经过 $this->storage->read包含执行,最终造成文件包含漏洞。

要访问漏洞的方法,必须是配置文件为:

1
//是否开启前台会员中心
2
'usercenter'            => true,

[90sec][https://forum.90sec.com/t/topic/1294] 上有人发出windows上面的利用方式。

先注册用户,之后上传带有php代码的头像,查看头像位置,最后访问

1
http://x.x.x.x/index.php/index/user/_empty?name=../uploads/xxxxxx.jpg

即可包含文件

如果含有其他的文件可控点,也是可以包含的,比如仍然使用低版本thinkphp的fastadmin的日志。包含的文件必须有后缀名,否则默认为 .html

修复

V1.0.0.20200920_beta已修复,官方删除了 application/index/User.php 内的 _empty() 方法。