码迷,mamicode.com
首页 > 其他好文 > 详细

PbootCMS2.07前台任意文件包含漏洞(复现)

时间:2020-05-21 13:14:17      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:roo   not   pil   正则   img   函数   sse   版本   theme   

0x00

审计对象:PbootCMS2.07
cms下载地址:
https://github.com/hnaoyun/PbootCMS/releases/tag/V2.0.7
参考文章:

https://xz.aliyun.com/t/7744#toc-1

漏洞代码

漏洞发生在 core/view/view.php

即解析模板文件的parser函数:

 // 解析模板文件
    public function parser($file)
    {
        // 设置主题
        $theme = isset($this->vars[‘theme‘]) ? $this->vars[‘theme‘] : ‘default‘;
        
        $theme = preg_replace(‘/\.\.(\/|\\\)/‘, ‘‘, $theme); // 过滤掉相对路径
        $file = preg_replace(‘/\.\.(\/|\\\)/‘, ‘‘, $file); // 过滤掉相对路径
        
        if (strpos($file, ‘/‘) === 0) { // 绝对路径模板
            $tpl_file = ROOT_PATH . $file;
        } elseif (! ! $pos = strpos($file, ‘@‘)) { // 跨模块调用
            $path = APP_PATH . ‘/‘ . substr($file, 0, $pos) . ‘/view/‘ . $theme;
            define(‘APP_THEME_DIR‘, str_replace(DOC_PATH, ‘‘, $path));
            if (! is_dir($path)) { // 检查主题是否存在
                error(‘模板主题目录不存在!主题路径:‘ . $path);
            } else {
                $this->tplPath = $path;
            }
            $tpl_file = $path . ‘/‘ . substr($file, $pos + 1);
        } else {
            // 定义当前应用主题目录
            define(‘APP_THEME_DIR‘, str_replace(DOC_PATH, ‘‘, APP_VIEW_PATH) . ‘/‘ . $theme);
            if (! is_dir($this->tplPath .= ‘/‘ . $theme)) { // 检查主题是否存在
                error(‘模板主题目录不存在!主题路径:‘ . APP_THEME_DIR);
            }
            $tpl_file = $this->tplPath . ‘/‘ . $file; // 模板文件
        }
        $note = Config::get(‘tpl_html_dir‘) ? ‘<br>同时检测到您系统中启用了模板子目录‘ . Config::get(‘tpl_html_dir‘) . ‘,请核对是否是此原因导致!‘ : ‘‘;
        file_exists($tpl_file) ?: error(‘模板文件‘ . APP_THEME_DIR . ‘/‘ . $file . ‘不存在!‘ . $note);
        $tpl_c_file = $this->tplcPath . ‘/‘ . md5($tpl_file) . ‘.php‘; // 编译文件
                                                                       
        // 当编译文件不存在,或者模板文件修改过,则重新生成编译文件
        if (! file_exists($tpl_c_file) || filemtime($tpl_c_file) < filemtime($tpl_file) || ! Config::get(‘tpl_parser_cache‘)) {
            $content = Parser::compile($this->tplPath, $tpl_file); // 解析模板
            file_put_contents($tpl_c_file, $content) ?: error(‘编译文件‘ . $tpl_c_file . ‘生成出错!请检查目录是否有可写权限!‘); // 写入编译文件
            $compile = true;
        }
        
        ob_start(); // 开启缓冲区,引入编译文件
        $rs = include $tpl_c_file;
        if (! isset($compile)) {
            foreach ($rs as $value) { // 检查包含文件是否更新,其中一个包含文件不存在或修改则重新解析模板
                if (! file_exists($value) || filemtime($tpl_c_file) < filemtime($value) || ! Config::get(‘tpl_parser_cache‘)) {
                    $content = Parser::compile($this->tplPath, $tpl_file); // 解析模板
                    file_put_contents($tpl_c_file, $content) ?: error(‘编译文件‘ . $tpl_c_file . ‘生成出错!请检查目录是否有可写权限!‘); // 写入编译文件
                    ob_clean();
                    include $tpl_c_file;
                    break;
                }
            }
        }
        $content = ob_get_contents();
        ob_end_clean();
        return $content;
    }

我们可以看到这个函数首先对传过来的参数进行过滤:

$file = preg_replace(‘/\.\.(\/|\\\)/‘, ‘‘, $file); // 过滤掉相对路径

这个函数过滤的实际上是过滤2个.和/与\(\\就是\)
但是却可以绕过,我们本地测试一下:
技术图片

这样就得到了后续我们想要的字符。
继续看代码:
之后生成模板文件

?$tpl_file?=?$this->tplPath?.?‘/‘?.?$file;?//?模板文件

然后编译文件

$tpl_c_file?=?$this->tplcPath?.?‘/‘?.?md5($tpl_file)?.?‘.php‘;?//?编译文件

之后就到了关键点

当编译文件不存在,或者模板文件修改过,则重新生成编译文件
我们可以看到他首先从缓存中判断编译文件存不存在,不存在则解析模板重新生成编译文件。

file_put_contents这个函数将$content写入,生成编译文件,include?$tpl_c_file; 包含我们的编译文件。
到这里我们的攻击思路已经很明确了,我们需要让parser函数的参数可以被控制,造造成任意文件包含。
找漏洞执行点,也就是找一个调用了parser函数的地方,且参数可控,比如能让我们传入入上面的目录穿越恶意字符造成任意文件读取。

漏洞执行点

前台控制器TagController中的index方法:
apps/home/controller/tagcontroller.php
技术图片

$tagstpl?=?request(‘tagstpl‘);

直接传入导致我们前台$tagstpl可控
这里::用来直接调用类中的属性或方法
所以调用parser函数,且直接拼接,那个正则不影响我们的paylaod。
$content?=?parent::parser($this->htmldir?.?$tagstpl);?//?框架标签解析
然后就是虽然这个$content前面被拼接了$this->htmldir,但是函数内部可以出现目录穿越,所以$this->htmldir这个路径并不影响。也就是说他是在生成编译文件时穿越的。
技术图片

技术图片

验证成功

漏洞修复

官方在2.08版本修改
技术图片

直接对TagController的正则进行了修改,强制限制了后缀名为html。

总结

这个漏洞用P3师傅的话来说就是
PbootCMS2.07内核处理缺陷导致的一个前台任意文件包含漏洞
他的内核函数在生成编译文件的时候造成任意文件读取,我们只要找到可控参数的parser调用就可以触发漏洞。
同时这次修复并没有对内核做出调整,所以想要绕过补丁可以往这个思路来找,看看哪里同样调用了可控参数的parser。
最后,膜P3师傅!

参考

https://xz.aliyun.com/t/7744#toc-0

PbootCMS2.07前台任意文件包含漏洞(复现)

标签:roo   not   pil   正则   img   函数   sse   版本   theme   

原文地址:https://www.cnblogs.com/wangtanzhi/p/12930074.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!