這道題真的是漲了我的知識,也確實interesting
而且,因為我想要加大刷題的量,不想碼字占用我太多的時間,所以未來的writeup的格式可能會很簡陋,但是一定會有重點,會有該有的東西。
開始~
題目:http://ctf5.shiyanbar.com/web/pcat/index.php
首先,還是web題的老套路,抓包,看源碼,找hint,審計代碼......
我們在網(wǎng)頁的注釋中發(fā)現(xiàn)了source.txt里面放著源碼,然后開始審計:
<?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);
?>
比較引人注意的是,這次的過濾,很全面,把我們常規(guī)思路大概都過濾掉了。
而且,后面的mysql_num_rows($query) == 1也讓我們看不到結(jié)果,于是沒有辦法,我只能猜測是基于時間的盲注,但是我們發(fā)現(xiàn)sleep benchmark以及括號都被過濾了。而且,就算前面的限制都過去,你也不知道pwd。
那么,這是用到了sql語句中的一個叫做rollup的東西,他是用在groupby后進(jìn)行數(shù)據(jù)統(tǒng)計的,與他類似的有一個叫做cube的,他和rollup的不同之處也就是我們要利用的地方,講道理,用cube也是可以的,因為對于單一分組來說,也就一組數(shù)據(jù)報表。但是嘗試發(fā)現(xiàn)不可以,這里不知道為什么。
rollup和cube呢,其實就是groupby的一個擴(kuò)展功能,叫做超級聚合,也就是對于分組數(shù)據(jù)進(jìn)行一下統(tǒng)計報表。講道理他是和聚合函數(shù)連用的,來產(chǎn)生一個合計的數(shù)據(jù),但是,同時他也會產(chǎn)生一個NULL的數(shù)據(jù)。
后來,我想了一下,為什么是這樣呢?
首先,我們構(gòu)造的sql里面groupby 卻沒有聚合,所以得到的就是單獨的一列內(nèi)容,然后在這單獨的一列上rollup得到的就是null
所以,只要我們的password不傳值進(jìn)去,我們就通過驗證了。
