PHP利用PCRE回溯次数限制绕过某些安全限制
字数 1261 2025-08-18 11:37:45
PCRE回溯次数限制绕过安全限制的深入分析与防御
1. 背景与问题描述
在PHP安全开发中,经常使用正则表达式来检测恶意输入,如PHP代码或SQL注入。然而,由于PCRE(Perl Compatible Regular Expressions)库的实现机制,存在一种通过触发回溯次数限制来绕过安全检测的攻击方式。
典型漏洞代码示例:
function is_php($data) {
return preg_match('/<\?.*[(`;?>].*/is', $data);
}
if(!is_php($input)) {
// fwrite($f, $input); // 写入文件操作
}
2. PCRE正则引擎原理
2.1 有限状态自动机
正则表达式属于可以被"有限状态自动机"接受的语言类,分为两种类型:
-
DFA (确定性有限状态自动机):
- 从起始状态开始,逐个字符读取输入
- 根据正则确定转移状态
- 直到匹配不上或走完整个输入
- 性能较好但不支持复杂功能
-
NFA (非确定性有限状态自动机):
- 从起始状态开始,逐个字符读取输入
- 与正则表达式进行匹配
- 如果匹配不上,则进行回溯尝试其他状态
- 支持更多功能但性能较差
PHP使用的PCRE库基于NFA实现。
2.2 回溯过程分析
以正则/<\?.*[(;?>].*/is匹配输入<?php phpinfo();//aaaaa`为例:
<\?匹配<?php phpinfo();//aaaaa的开头<?.*贪婪匹配剩余所有字符php phpinfo();//aaaaa- 尝试匹配字符类
[(;?>]`但已到字符串末尾 - 开始回溯:每次回退一个字符尝试匹配
- 直到回退到
;位置,完成匹配
此过程涉及大量回溯操作,具体次数取决于输入字符串长度。
3. PHP的PCRE回溯限制
3.1 pcre.backtrack_limit设置
PHP为防止正则表达式拒绝服务攻击(ReDoS),设置了回溯次数上限:
var_dump(ini_get('pcre.backtrack_limit')); // 默认1000000(100万)
3.2 超过限制的后果
当回溯次数超过限制时:
preg_match()返回false而非1(匹配成功)或0(匹配失败)- 可通过
preg_last_error()检测错误类型:var_dump(preg_last_error() === PREG_BACKTRACK_LIMIT_ERROR); // true
3.3 漏洞利用方法
通过构造超长输入使正则匹配达到回溯限制:
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. 其他常见漏洞场景
4.1 SQL注入WAF绕过
漏洞代码示例:
if(preg_match('/SELECT.+FROM.+/is', $input)) {
die('SQL Injection');
}
利用方式:通过超长字符串触发回溯限制
4.2 非贪婪模式漏洞
漏洞代码示例:
if(preg_match('/UNION.+?SELECT/is', $input)) {
die('SQL Injection');
}
利用原理:
- 输入
UNION/*aaaaa*/SELECT .+?非贪婪匹配遇到/停止S尝试匹配*失败- 回溯使
.+?匹配* - 重复此过程导致大量回溯
5. 修复方案
5.1 严格检查返回值
必须使用全等(===)判断preg_match返回值:
if(is_php($input) === 0) {
// 安全处理逻辑
}
5.2 其他防御措施
-
限制输入长度:
if(strlen($input) > 1000) { die('Input too long'); } -
使用更高效的正则:
- 避免过度使用
.*和.+ - 使用更精确的字符类
- 避免过度使用
-
组合防御策略:
function is_php($data) { if(strlen($data) > 1000) return true; return preg_match('/<\?.*[(`;?>].*/is', $data) === 1; }
6. 总结
- PCRE的NFA实现存在回溯特性
- PHP默认回溯限制为100万次
- 不正确的返回值检查会导致安全绕过
- 防御关键在于:
- 严格使用
===判断返回值 - 限制输入长度
- 优化正则表达式模式
- 严格使用
通过深入理解PCRE工作原理和PHP的实现细节,开发者可以更有效地防御此类安全漏洞。