感觉学到挺多的一道题
附上源码(在解题链接根目录打开sourec.txt)
'."
";
echo ''."
";
echo ''."
";
echo ''."
";
echo ''."
";
echo ''."
";
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);
?>
解释一些函数的意思
PHP mysql_fetch_array() 函数
mysql_fetch_array(data,array_type)
data 可选。规定要使用的数据指针。该数据指针是 mysql_query() 函数产生的结果。
array_type 可选。规定返回哪种结果。可能的值:
MYSQL_ASSOC - 关联数组
MYSQL_NUM - 数字数组
MYSQL_BOTH - 默认。同时产生关联和数字数组
PHP mysql_query() 函数
mysql_query(query,connection)
query 必需。规定要发送的 SQL 查询。注释:查询字符串不应以分号结束。
connection 可选。规定 SQL 连接标识符。如果未规定,则使用上一个打开的连接。
PHP mysql_num_rows() 函数
mysql_num_rows() 函数返回结果集中行的数目
mysql_num_rows(data)
data 必需。结果集。该结果集从 mysql_query() 的调用中得到
preg_match — 执行匹配正则表达式
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
pattern 要搜索的模式,字符串类型。
subject 输入字符串。
matches 如果提供了参数matches,它将被填充为搜索结果。 $matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。
flags flags可以被设置为以下标记值:
PREG_OFFSET_CAPTURE
如果传递了这个标记,对于每一个出现的匹配返回时会附加字符串偏移量(相对于目标字符串的)。 注意:这会改变填充到matches参数的数组,使其每个元素成为一个由 第0个元素是匹配到的字符串,第1个元素是该匹配字符串 在目标字符串subject中的偏移量。
GROUP BY WITH ROLLUP 改善统计性能
使用 GROUP BY 的 WITH ROLLUP 字句可以检索出更多的分组聚合信息,它不仅仅能像一般的 GROUP BY 语句那样检索出各组的聚合信息,还能检索出本组类的整体聚合信息
is_array 判断变量类型是否为数组类型。
PHP implode() 函数 把数组元素组合为字符串
从源码中可以知道这些全都被过滤了:and|select|from|where|union|join|sleep|benchmark|,|\(|\)
https://b.zlweb.cc/shiyanbar-yqstdrg-writeup.html
分析一下,可以知道,要想显示flag值,需要满足以下条件:
1.需要绕过AttackFilter过滤 2.需要让mysql_num_rows的结果为1 3.需要$key['pwd']的值和提交的$_POST['pwd']的值相等 看过滤列表,并没有过滤or,所以我们可以使用' or ''=''的句型,尝试提交post数据:uname=' or ''=''--+&pwd=xxx,此时显示:一颗赛艇,然后并没有满足条件2,后来看到如下提示: 表中只有uname和pwd字段 with rollup 后来查了下用法(关于with rollup的介绍:https://dev.mysql.com/doc/refman/5.7/en/group-by-modifiers.html),接着提交post数据:uname=' or ''='' group by pwd with rollup--+&pwd=xxx,依然显示一颗赛艇,后来发现需要使用limit 1 offset x来确定数据,因为只能显示1条,为了条件3,我们需要让其返回pwd为NULL的那一行,而且注释需要使用#,不能用--+。 条件2也满足了,下面就是满足条件3,此时通过上面构造的payload,pwd的值为NULL,所以我们只需要pwd什么都不写,默认就为NULL了,于是构造完整的payload如下: uname=' or ''='' group by pwd with rollup limit 1 offset 2--+&pwd= 因为with rollup的原因,会多显示一条,所以offset应该设为2,提交后就可以正常显示flag