代码审计之lvyecms后台getshell | Sunbet
登录
  • 欢迎进入Sunbet!
  • 如果您觉得Sunbet对你有帮助,那么赶紧使用Ctrl+D 收藏Sunbet并分享出去吧
  • 您好,这里是Sunbet!

代码审计之lvyecms后台getshell

Sunbet_安全防护 申博 49次浏览 已收录 0个评论

准备审计

码云上下载最新的lvyecms

地址:https://gitee.com/lvyecms/lvyecms?_from=gitee_searchs

审计开始

首先看网站目录结构

代码审计之lvyecms后台getshell

找到入口文件 index.php

代码审计之lvyecms后台getshell

标准的thinkphp3.2风格,具体介绍见官方文档:http://document.thinkphp.cn/manual_3_2.html

进入lvyecms/Application目录,查看存在哪些模块

代码审计之lvyecms后台getshell

一般进行代码审计时,先看前台代码,再看后台代码,但lvyecms都是需要后台权限的模块,所以不用管先后顺序,直接看Template模块

代码审计之lvyecms后台getshell

审计Template模块代码,可以发现自定义页面

代码审计之lvyecms后台getshell

//增加自定义页面 
    public function add() {
        if (IS_POST) {
            $model = D('Template/Customtemp');
            if ($model->create($_POST)) {
                $tempid = $model->add();
                if ($tempid) {
                    $this->Html->createHtml((int) $tempid);
                    $this->success("添加自定义页面成功!", U('Custompage/index'));
                } else {
                    $this->error("添加自定义页面失败!");
                }
            } else {
                $this->error($model->getError());
            }
        } else {
            $this->display();
        }
    }

先将数据写进数据库里,然后调用createHtml函数,下面几个自定义页面都是这样的逻辑。

Ripstech Java Security 2019 Calendar复现系列(一)

Day1 XXE之SAXBuilder解析 代码 Day 1 https://www.ripstech.com/java-security-calendar-2019/ 漏洞点 漏洞产生的主要是SAXBuilder.build()这个函数易受到XXE攻击。SAXBuilder类用于解析xml,攻击者可以上传包含恶意xml的文件来发起XXE攻击。 代码中ImportDocument这个类的作用是从”uploaded_office_doc.odt”文件中读取内容,以zip格式读入。通过对该zip文件中的所有文件进行遍历,判断是否含有content.xml文件。若其中含有content.xml文件,则将其通过org.jdom2.input.SAXbuilder.build()进行解析,若content.xml为恶意的xml文件,则产生XXE。 复现过程 1. 环境 IDEA+Maven 2. 添加Main函数 Day1.java packag

跟进createHtml函数,在跟进createHtml函数之前,先要知道$this->Html这个方法是从哪里来的,跟进这个控制器的父类(Common\Controller\AdminBase):

代码审计之lvyecms后台getshell

发现父类中也没有定义该函数,跟进父类的父类查看

class LvyeCMS extends \Think\Controller {

    //缓存
    public static $Cache = array();
    //当前对象
    private static $_app;

    public function __get($name) {
        $parent = parent::__get($name);
        if (empty($parent)) {
            return Components::getInstance()->$name;
        }
        return $parent;
    }

    public function __construct() {
        parent::__construct();
        self::$_app = $this;
    }
    ...
}

这里没有定义,但定义了__get()魔术方法,魔术方法中先调用了父类的__get的魔术方法,get方法只是获取模板显示变量的值,继续向下审计,进入下面的代码块

public function get($name='') {
        return $this->view->get($name);      
    }

    public function __get($name) {
        return $this->get($name);
    }

跟进Components类中的getInstance方法,这个方法是实例化自身对象

static public function getInstance($_components = array()) {
        static $systemHandier;
        if (empty($systemHandier)) {
            $systemHandier = new Components($_components);
        }
        return $systemHandier;
    }

上面的类中也定义了__get魔术方法

public function __get($name) {
        if (isset(self::$_components[$name])) {
            $components = self::$_components[$name];
            if (!empty($components['class'])) {
                $class = $components['class'];
                if ($components['path'] && !class_exists($class, false)) {
                    import($components['path'], PROJECT_PATH);
                }
                unset($components['class'], $components['path']);
                $this->$name = \Think\Think::instance($class);
                return $this->$name;
            }
        }
    }

先判断$name是不是类中数组的key,是就返回一个对象,$name是Html,查看数组中对应的类在哪里,跟进:

static private $_components = array(
        'Url' => array(
            'class' => '\\Libs\\System\\Url',
            'path' => 'Libs.System.Url',
        ),
        'Cloud' => array(
            'class' => '\\Libs\\System\\Cloud',
            'path' => 'Libs.System.Cloud',
        ),
        'CloudDownload' => array(
            'class' => '\\Libs\\System\\CloudDownload',
            'path' => 'Libs.System.CloudDownload',
        ),
        'Html' => array(
            'class' => '\\Libs\\System\\Html',
            'path' => 'Libs.System.Html',
        ),
        'UploadFile' => array(
            'class' => '\\UploadFile',
        ),
        'Dir' => array(
            'class' => '\\Dir',
            'path' => 'Libs.Util.Dir',
        ),
        'Content' => array(
            'class' => '\\Libs\\System\\Content',
            'path' => 'Libs.System.Content',
        ),
        'ContentOutput' => array(
            'class' => '\\content_output',
        ),
    );

回到控制器类中,查看调用的方法

public function add() {
        if (IS_POST) {
            $model = D('Template/Customtemp');
            if ($model->create($_POST)) {
                $tempid = $model->add();
                if ($tempid) {
                    $this->Html->createHtml((int) $tempid);
                    $this->success("添加自定义页面成功!", U('Custompage/index'));
                } else {
                    $this->error("添加自定义页面失败!");
                }
            } else {
                $this->error($model->getError());
            }
        } else {
            $this->display();
        }
    }
    ...

得知调用的是createHtml这个方法
到Html.class.php文件中,查看此方法:

public function createHtml($data = '') {
        if (empty($data)) {
            if (!empty($this->data)) {
                $data = $this->data;
                // 重置数据
                $this->data = array();
            } else {
                $this->error = '没有数据';
                return false;
            }
        } else if (is_integer($data)) {
            $data = M('Customtemp')->where(array('tempid' => $data))->find();
            if (empty($data)) {
                $this->error = '没有数据';
                return false;
            }
        }
        //模板内容
        $temptext = $data['temptext'];
        if (empty($temptext)) {
            return true;
        }
        //初始化一些模板分配变量
        $this->assignInitialize();
        //生成文件名,包含后缀
        $filename = $data['tempname'];
        //生成路径
        $htmlpath = SITE_PATH . $data['temppath'] . $filename;
        // 页面缓存
        ob_start();
        ob_implicit_flush(0);
        parent::show($temptext);
        // 获取并清空缓存
        $content = ob_get_clean();
        //检查目录是否存在
        if (!is_dir(dirname($htmlpath))) {
            // 如果静态目录不存在 则创建
            mkdir(dirname($htmlpath), 0777, true);
        }
        //写入文件
        if (false === file_put_contents($htmlpath, $content)) {
            E("自定义页面生成失败:{$htmlpath}");
        }
        return true;
    }
    ....

发现从数据库中读取文件信息,直接生成,没有过滤。

漏洞验证

代码审计之lvyecms后台getshell

代码审计之lvyecms后台getshell

代码审计之lvyecms后台getshell


Sunbet|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明代码审计之lvyecms后台getshell
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址