YCCMS是一款PHP版轻量级CMS建站系统,程序页面设计简洁,生成静态html,后台功能强大,利于优化、超强收录、超强排名,适合做关键词排名、淘宝客程序,是个人、企业建站的理想选择。
审计版本:YCCMS建站系统 3.3
更新时间:2018-08-29
下载源码,本地phpstudy搭建环境。
打开seay,自动审计cms代码,确定审计范围和目标点。
浏览CNVD,看看已经披露的漏洞有哪些。
接下来就是逐一进行有目标的审计,看看能不能复现出来。
确定漏洞点,/public/class/Factory.class.php
关键代码:
class Factory{
static private $_obj=null;
static public function setAction(){
$_a=self::getA();
if (in_array($_a, array('admin', 'nav', 'article','backup','html','link','pic','search','system','xml','online'))) {
if (!isset($_SESSION['admin'])) {
header('Location:'.'?a=login');
}
}
if (!file_exists(ROOT_PATH.'/controller/'.$_a.'Action.class.php')) $_a = 'Index';
eval('self::$_obj = new '.ucfirst($_a).'Action();');
return self::$_obj;
}
static public function setModel() {
。。。
}
static public function getA(){
。。。
}
}
分析 setAction() 方法,首先调用 getA() 方法获取 get 过来的 a 参数进行跳转检查操作,然后 file_exists() 函数进行检查页面文件是否存在,最后调用 eval() 执行PHP代码。
我们想要利用 eval 执行代码,就得先成功逃逸 file_exists 函数。
file_exists() 主要作用是检查文件是否存在,但是这个函数在进行检查会有一个bug,如 /controller/admin;/…/,函数允许路径中有一些特殊字符,并且遇到 /…/ 会返回到上级目录,可以利用这个策略逃逸出 file_exists() 函数检查。
payload:Factory();phpinfo();//../
全局搜索,看看那里实例化了 Factory 这个类。
可以看到 /config/run.inc.php 有实例化,那再看看那里包含了该文件。
可以看到 /admin/index.php 和 /config/count.php 包含了该文件。
漏洞复现:
前台似乎没有找到,后台找到一处上传点。
处理其代码逻辑在 /public/class/LogoUpload.class.php,关键代码如下:
//构造方法,初始化
public function __construct($_file,$_maxsize) {
$this->error = $_FILES[$_file]['error'];
$this->maxsize = $_maxsize / 1024;
$this->type = $_FILES[$_file]['type'];
$this->path = ROOT_PATH.'/'.UPLOGO;
$this->name = $_FILES[$_file]['name'];
$this->tmp = $_FILES[$_file]['tmp_name'];
$this->checkError(); //验证错误
$this->checkType(); //验证类型
$this->checkPath(); //验证目录
$this->moveUpload(); //移动文件
}
绕过很简单,上传一个PNG格式,大小不超过2M的图片,bp抓包,修改内容为php一句话,后缀改为php。
有警告不要紧,php文件其实已经生成了。
使用菜刀去连接就行了。
确定漏洞点,/controller/PicAction.class.php
关键代码如下:
//图片控制器
class PicAction extends Action{
public function __construct(){
parent::__construct();
}
public function index(){
。。。
}
public function delall(){
if(isset($_POST['send'])){
if(validate::isNullString($_POST['pid'])) tool::layer_alert('没有选择任何图片!','?a=pic',7);
$_fileDir=ROOT_PATH.'/uploads/';
foreach($_POST['pid'] as $_value){
$_filePath=$_fileDir.$_value;
if(!unlink($_filePath)){
tool::layer_alert('图片删除失败,请设权限为777!','?a=pic',7);
}else{
header('Location:?a=pic');
}
}
}
}
}
可以看出 filePath 中拼接了 post 过来的 pid 参数,然后执行 unlink 删除该路径的文件。
pid 参数是可控的,这就造成了漏洞。
漏洞触发处:
先在本地创建一个测试文件,test.txt。
点击删除图片,bp抓包,修改 pid 参数。
成功删除文件。