码云上下载最新的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
模块代码,可以发现自定义页面
//增加自定义页面 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):
发现父类中也没有定义该函数,跟进父类的父类查看
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; } ....
发现从数据库中读取文件信息,直接生成,没有过滤。