利用正则回溯最大次数上限绕过preg-ag真人国际厅网站

  1. 没有回溯的匹配

假设我们的正则是/ab{1,3}c/,其可视化形式是:

而当目标字符串是”abbbc”时,就没有所谓的“回溯”。其匹配过程是:

其中子表达式b{1,3}表示“b”字符连续出现1到3次。

  1. 有回溯的匹配

如果目标字符串是”abbc”,中间就有回溯。

图中第5步有红颜色,表示匹配不成功。此时b{1,3}已经匹配到了2个字符“b”,准备尝试第三个时,结果发现接下来的字符是“c”。那么就认为b{1,3}就已经匹配完毕。然后状态又回到之前的状态(即第6步,与第4步一样),最后再用子表达式c,去匹配字符“c”。当然,此时整个表达式匹配成功了。

图中的第6步,就是“回溯”。

像{1,3}这种属于贪婪量词他会尽可能多的去匹配,匹配不到时在回溯

var string = "12345"; var regex = /(\d{1,3})(\d{1,3})/; console.log( string.match(regex) ); // => ["12345", "123", "45", index: 0, input: "12345"]

其中,前面的\d{1,3}匹配的是”123″,后面的\d{1,3}匹配的是”45″。

而惰性量词则相反

惰性量词就是在贪婪量词后面加一个问号

var string = "12345"; var regex = /(\d{1,3}?)(\d{1,3})/; console.log( string.match(regex) ); // => ["1234", "1", "234", index: 0, input: "12345"]

其中\d{1,3}?只匹配到一个字符”1″,而后面的\d{1,3}匹配了”234″。

虽然惰性量词不贪,但也会有回溯的现象。比如正则是:

目标字符串是”12345″,匹配过程是:

虽然惰性量词不贪,但是为了整体匹配成,没办法,也只能给你多塞点了。因此最后\d{1,3}?匹配的字符是”12″,是两个数字,而不是一个。

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

dfa: 从起始状态开始,一个字符一个字符地读取输入串,并根据正则来一步步确定至下一个转移状态,直到匹配不上或走完整个输入 nfa:从起始状态开始,一个字符一个字符地读取输入串,并与正则表达式进行匹配,如果匹配不上,则进行回溯,尝试其他状态

由于 nfa 的执行过程存在回溯,所以其性能会劣于 dfa,但它支持更多功能。大多数程序语言都使用了 nfa 作为正则引擎,其中也包括 php 使用的 pcre 库。

利用正则回溯最大次数上限进行绕过

源码:

].*/is', $data); } if(empty($_files)) { die(show_source(__file__)); } $user_dir = 'data/' . md5($_server['remote_addr']); $data = file_get_contents($_files['file']['tmp_name']); if (is_php($data)) { echo "bad request"; } else { @mkdir($user_dir, 0755); $path = $user_dir . '/' . random_int(0, 10) . '.php'; move_uploaded_file($_files['file']['tmp_name'], $path); header("location: $path", true, 303); }

一看就是要上传文件进行rce了

但是这里的正则表达式ban掉了

上文提到的正则回溯然后量过大必然会消耗大量的时间甚至会被dos攻击

php 为了防止正则表达式的拒绝服务攻击(redos),给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit。我们可以通过 var_dump(ini_get(‘pcre.backtrack_limit’));的方式查看当前环境下的上限。回溯次数上限默认是 100 万。那么,假设我们的回溯次数超过了 100 万,会出现什么现象呢?preg_match 返回的非 1 和 0,而是 false。

如果长度超过了100万,则会返回false

所以我们可以用超过100万的长度来是preg_match语句返回false从而不进入if循环来达到上传文件的目的

poc: import requests from io import bytesio url = "http://xxx.xxx.xxx/" files = { 'file': bytesio(b'aaa

然后找到路径,这里可能是ban掉了system这些,所以我直接用蚁剑连接即可

很多基于 php 的 waf,如:

均存在上述问题,通过大量回溯可以进行绕过。

另外,我遇到更常见的一种 waf 是:

这里涉及到了正则表达式的「非贪婪模式」。在 nfa 中,如果我输入 union/aaaaa/select,这个正则表达式执行流程如下:

. ? 匹配到/ 因为非贪婪模式,所以. ? 停止匹配,而由 s 匹配* s 匹配*失败,回溯,再由. ? 匹配* 因为非贪婪模式,所以. ? 停止匹配,而由 s 匹配 a s 匹配 a 失败,回溯,再由. ? 匹配 a ... 回溯次数随着 a 的数量增加而增加。所以,我们仍然可以通过发送大量 a,来使回溯次数超出 pcre.backtrack_limit 限制,进而绕过 waf:

其实在官方文档里面介绍了

用preg_match一定要用===来判断返回值

参考链接:

原文链接:https://xz.aliyun.com/t/10219

网络摘文,本文作者:15h,如若转载,请注明出处:https://www.15cov.cn/2023/08/27/利用正则回溯最大次数上限绕过preg_match/

发表评论

邮箱地址不会被公开。 必填项已用*标注

网站地图