FastAdmin前台漏洞getshell分析
影响版本
V1.0.0.20200506_beta
分析
文件包含
根据官网的修复方法
可以看到产生漏洞的位置 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