先提出一段代码,是i春秋上面的移到ctf题目的代码,也是需要我们绕过的代码:
function areyouok($greeting){
return preg_match('/Merry.*Christmas/is',$greeting);
}
$greeting=@$_POST['greeting'];
if(!areyouok($greeting)){
if(strpos($greeting,'Merry Christmas')!==false){
echo 'Merry Christmas. '.'flag{xxxxxx}';
}else{
echo 'Do you know .swp file?';
}
}else{
echo 'Do you know PHP?';
}
?>
很快就可以知道,使用数组就可以绕过
payload:
greeting[]=Merry Christmas&greeting[]=123
但是如果禁止传递数组的时候怎么绕过?
示例代码(来自i春秋ctf):
function areyouok($greeting){
return preg_match('/Merry.*Christmas/is',$greeting);
}
$greeting=@$_POST['greeting'];
if(!is_array($greeting)){
if(!areyouok($greeting)){
if(strpos($greeting,'Merry Christmas')!==false){
echo 'Merry Christmas. '.'flag{xxxxxx}';
}else{
echo 'Do you know .swp file?';
}
}else{
echo 'Do you know PHP?';
}
}
?>
其中判断了greeting不能为数组,这时就涉及到一个关于正则最大回溯的问题了
正则(pcre)最大回溯:
在PHP的pcre扩展中提供了两个设置选项:
pcre.backtrack_limit //最大回溯数
pcre.recursion_limit //最大嵌套数
backtrack_limit的默认值为100000。
而什么是回溯?
在正则匹配当中,如果存在符号 " .*? " ,那么匹配的时候便会使用非贪婪模式。非贪婪模式匹配原理简单来说就是, 在可配也可不配的情况下, 优先不匹配. 记录备选状态, 并将匹配控制交给正则表达式的下一个匹配字符, 当之后的匹配失败的时候, 再回溯, 进行匹配。
举例来说:
源字符串: aaab
正则: .*?b
匹配过程开始的时候, “.*?”首先取得匹配控制权, 因为是非贪婪模式, 所以优先不匹配, 将匹配控制交给下一个匹配字符”b”, “b”在源字符串位置1匹配失败(“a”), 于是回溯, 将匹配控制交回给”.*?”, 这个时候, “.*?”匹配一个字符”a”, 并再次将控制权交给”b”, 如此反复, 最终得到匹配结果, 这个过程中一共发生了3次回溯。
所以在题目当中,只要匹配时的回溯次数超过了100000,就会导致匹配失败而退出,从而绕过限制。
所以我们的payload应该为:
greeting=Merry Christmas //后面省略数万个字符
这样即可绕过限制。
参考链接: