准备审计
码云上下载最新的lvyecms
地址:https://gitee.com/lvyecms/lvyecms?_from=gitee_searchs
审计开始
首先看网站目录结构
找到入口文件 index.php
thinkphp3.2
风格,具体介绍见官方文档:http://document.thinkphp.cn/manual_3_2.html
进入lvyecms/Application
目录,查看存在哪些模块
一般进行代码审计时,先看前台代码,再看后台代码,但lvyecms都是需要后台权限的模块,所以不用管先后顺序,直接看Template
模块
审计Template
模块代码,可以发现自定义页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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
函数,下面几个自定义页面都是这样的逻辑。
跟进createHtml
函数,在跟进createHtml
函数之前,先要知道$this->Html
这个方法是从哪里来的,跟进这个控制器的父类(Common\Controller\AdminBase):
发现父类中也没有定义该函数,跟进父类的父类查看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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方法只是获取模板显示变量的值,继续向下审计,进入下面的代码块
1 2 3 4 5 6 7
| public function get($name='') { return $this->view->get($name); }
public function __get($name) { return $this->get($name); }
|
跟进Components类中的getInstance
方法,这个方法是实例化自身对象
1 2 3 4 5 6 7
| static public function getInstance($_components = array()) { static $systemHandier; if (empty($systemHandier)) { $systemHandier = new Components($_components); } return $systemHandier; }
|
上面的类中也定义了__get
魔术方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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,查看数组中对应的类在哪里,跟进:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| 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', ), );
|
回到控制器类中,查看调用的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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文件中,查看此方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| 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; } ....
|
从数据库中读取文件信息,直接生成,没有过滤。
漏洞验证