正则表达式回溯:
当涉及到正则表达式的回溯时,让我们来看一个具体的例子。
考虑以下正则表达式模式 a+b
,其中 a+
表示匹配一个或多个连续的字符 "a",b
表示匹配字符 "b"。
现在,假设有一个输入字符串为 "aaab",我们试图将这个字符串与模式进行匹配。以下是回溯的过程:
-
引擎开始尝试匹配
a+
,它找到了第一个 "a"。 -
然后引擎尝试匹配更多的 "a",发现了两个额外的 "a"。
-
此时,引擎已经匹配了三个 "a",接下来它尝试匹配字符 "b"。
-
因为输入字符串中的下一个字符是 "b",引擎成功地匹配了 "b",整个匹配成功。
但是,如果我们考虑一个不匹配的场景,比如输入字符串为 "aaac"。在这种情况下,回溯过程如下:
-
引擎开始尝试匹配
a+
,它找到了第一个 "a"。 -
然后引擎尝试匹配更多的 "a",发现了两个额外的 "a"。
-
此时,引擎已经匹配了三个 "a",接下来它尝试匹配字符 "b"。
-
由于输入字符串中的下一个字符是 "c",引擎无法匹配 "b"。
-
这意味着整个模式匹配失败。引擎开始回溯,尝试其他可能的匹配路径。
-
引擎回溯到第二个字符 "a",重新尝试匹配
a+
。 -
引擎再次找到了两个额外的 "a",然后尝试匹配字符 "b"。
-
由于输入字符串中的下一个字符仍然是 "c",引擎仍然无法匹配 "b"。
-
再次回溯,引擎继续尝试其他的匹配路径,但都失败了。
-
最终,整个模式匹配失败。
这个例子展示了当模式无法匹配输入时,正则表达式引擎会回溯到之前的位置,尝试其他可能的匹配路径。当处理复杂的正则表达式或大量数据时,回溯可能会导致性能下降。
reDOS攻击简介:
Redos(正则表达式拒绝服务攻击)是一种针对使用正则表达式的应用程序的一种类型的拒绝服务攻击。
在正则表达式中,存在一些复杂的模式,称为“可回溯的”(Backtracking)。当使用这些模式来匹配字符串时,可能会导致回溯操作消耗大量的时间和计算资源。
攻击者可以构造特定的输入,使得正则表达式的回溯机制不断进行操作,耗尽大量的 CPU 时间和内存资源。这导致服务器无法处理其他正常的请求,造成拒绝服务。
计算(回溯)
根据NOSEC研究发表显示:计算机在处理正则表达式的时候可以说是非常愚蠢,虽然看上去它们有很强的计算能力。当你需要用x*y
表达式对字符串xxxxxxxxxxxxxx
进行匹配时,任何人都可以迅速告诉你无匹配结果,因为这个字符串不包含字符y。但是计算机的正则表达式引擎并不知道!它将执行以下操作
xxxxxxxxxxxxxx # 不匹配
xxxxxxxxxxxxxx # 回溯
xxxxxxxxxxxxx # 不匹配
xxxxxxxxxxxxx # 回溯
xxxxxxxxxxxx # 不匹配
xxxxxxxxxxxx # 回溯
xxxxxxxxxxx # 不匹配
xxxxxxxxxxx # 回溯
>>很多很多步骤
xx # 不匹配
x # 回溯
x # 不匹配
# 无匹配结果
你不会以为结束了吧?这只是第一步!
现在,正则表达式引擎将从第二个x开始匹配,然后是第三个,然后是第四个,依此类推到第14个x。
最终总步骤数为256。
它总共需要256步才能得出无匹配结果这一结论。计算机在这方面真的很蠢。
同样,如果你使用非贪婪匹配,x*?y
表达式会从一个字母开始匹配,直到尝试过所有的可能,这和贪婪匹配一样愚蠢。
题目演示:
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-13 05:19:40
*/
error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['f'])){
$f = (String)$_POST['f'];
if(preg_match('/.+?ctfshow/is', $f)){
die('bye!');
}
if(stripos($f,'36Dctfshow') === FALSE){
die('bye!!');
}
echo $flag;
}
这里POST的字符串如果包含了ctfshow那就直接die了,但是后面stripos是
查找 "php" 在字符串中第一次出现的位置:
<?php echo stripos("You love php, I love php too!","PHP"); ?>
输出:9
后面必定得返回true才行,也就是说必须包含36Dctfshow,似乎进去了死局,但是别忘了我们是学习过reDOS攻击的,PHP 为了防止reDOS攻击,
在PHP的pcre扩展中, 提供了俩个设置项.
- 1. pcre.backtrack_limit //最大回溯数
- 2. pcre.recursion_limit //最大嵌套数
默认的backtarck_limit是100000(10万)
参考文献:深悉正则(pcre)最大回溯/递归限制 - 风雪之隅 (laruence.com)
这里我们就直接使得对面超过最大回溯,直接返回false就好了
脚本:
<?php
echo str_repeat('very', '250000').'36Dctfshow';
接下来直接运行脚本post发过去就好了
主流预防reDOS攻击方法:
为了预防 Redos(正则表达式拒绝服务)攻击,可以采取以下措施:
-
避免使用可回溯的复杂正则表达式:尽量避免使用可回溯的模式,特别是包含量词的贪婪匹配(如使用
.*
或.+
)和嵌套组合的模式。优化正则表达式,使其更加精确和高效。 -
设置适当的时间限制:在处理正则表达式时,设置合适的时间限制,以防止一个匹配过程消耗过多的时间。可以使用 PHP 的
set_time_limit
函数来设置最大的执行时间。 -
对输入进行限制和过滤:对于接受用户输入的正则表达式,实施输入验证和过滤措施,限制输入的长度和字符类型,避免恶意构造的输入触发回溯操作。
-
限制匹配范围:根据应用需求,尽量缩小正则表达式的匹配范围。例如,指定具体的字符集和匹配模式,而不是使用更宽泛的通配符。
-
定期更新正则表达式引擎:保持正则表达式引擎的及时更新,以确保它们拥有最新的安全补丁和性能优化。
-
使用限制资源的匹配操作:在处理大量或复杂输入时,可以限制正则表达式引擎的处理资源,如匹配回溯深度、匹配重复次数、递归限制等。这可以通过配置正则表达式引擎或使用专门的 PCRE 库来实现。
-
审查和测试正则表达式:对使用的正则表达式进行审查和测试,特别关注复杂模式和可能导致回溯的部分。使用测试工具和输入集合来评估正则表达式的性能和安全性。