命令执行

0x01 命令注入

PHP命令注入攻击漏洞是PHP应用程序中常见的脚本漏洞之一,国内著名的Web应用程序Discuz!、DedeCMS等都曾经存在过该类型漏洞。

Command Injection,即命令注入攻击,是指由于Web应用程序对用户提交的数据过滤不严格,导致黑客可以通过构造特殊命令字符串的方式,将数据提交至Web应用程序中,并利用该方式执行外部程序或系统命令实施攻击,非法获取数据或者网络资源等。

0x02 命令注入原因

PHP命令注入攻击:
PHP命令注入攻击存在的主要原因是Web应用程序员在应用PHP语言中一些具有命令执行功能的函数时,对用户提交的数据内容没有进行严格的过滤就带入函数中执行而造成的。例如,当黑客提交的数据内容为向网站目录写入PHP文件时,就可以通过该命令注入攻击漏洞写入一个PHP后门文件,进而实施进一步的渗透攻击。
在PHP中,可以执行命令的函数有system()、exec()、shell_exex()、passthru()、pcntl_exex()、popen()、proc_open(),一共七个函数,另外反引号(`)也可以执行命令,不过这种方法也是调用的shell_exec()函数。
PHP中可以使用下列四个函数来执行外部的应用程序或函数:system()、exec()、passthru()、shell_exec(),四个函数的原型如下:

1
2
3
4
5
6
7
8
string system(string command, int &return_var)
command 要执行的命令; return_var 存放执行命令的执行后的状态值。
string exec (string command, array &output, int &return_var)
command 要执行的命令,output 获得执行命令输出的每一行字符串,return_var 存放执行命令后的状态值。
void passthru (string command, int &return_var)
command 要执行的命令,return_var 存放执行命令后的状态值。
string shell_exec (string command)
command 要执行的命令,如下例所示,表示通过提交http://www.sectop.com/ex1.php?dir=| cat /etc/passwd操作,执行命令变成了system("ls -al | cat /etc/passwd"),输出/etc/passwd 文件的具体内容。

//ex1.php

<?php
$dir = $_GET["dir"]; 
if (isset($dir)) 
{ 
    echo ""; 
    system("ls -al ".$dir); 
    echo ""; 
} 
?> 

popen()、proc_open()函数不会直接返回执行结果,而是返回一个文件指针。
popen()需要两个参数,一个是执行的命令,另一个是指针文件的连接模式,有r和w代表读和写。

<?php
popen('whoami' >>D:/test.txt','r');
?>

执行完之后可以在D盘根目录看到test.txt文件,内容为用户名。

&与&&与|的区别
在Linux上,上面的;也可以用|、||代替
;前面的执行完执行后面的
|是管道符,显示后面的执行结果
||当前面的执行出错时执行后面的
在Windows上,不能用;可以用&、&&、|、||代替
&前面的语句为假则直接执行后面的
&&前面的语句为假则直接出错,后面的也不执行
|直接执行后面的语句
||前面出错执行后面的
Command 1&&Command 2
先执行Command 1,执行成功后执行Command 2,否则不执行Command 2
Command 1&Command 2
先执行Command 1,不管是否成功,都会执行Command 2

“|”是管道符,表示将Command 1的输出作为Command 2的输入,并且只打印Command 2执行的结果。

0x03 挖掘经验

大部分直接搜索关键函数进行漏洞挖掘。

0x04 漏洞防范

PHP中命令注入攻击漏洞带来的危害和影响很严重。防范命令注入攻击漏洞的存在可以通过以下几种方法。

1、尽量不要执行外部的应用程序或命令。
2、使用自定义函数或函数库实现外部应用程序或命令的功能。
3、 在执行system、eval等命令执行功能的函数前,确定参数内容。
4、escapeshellcmd()函数会转义命令中的所有shell元字符来完成工作。这些元字符包括:#&;`,|*?~<>^()[]{}$\。例如写入一句话可被过滤 ,所以命令无法执行成功,无法生成一句话文件。

1
2
3
<?php
echo(escapeshellcmd($_GET['cmd']));
?>


可以看到这些字符过滤的方法就是在前面加了一个^符号,而在Linux下则是在子父母前面加了反斜杠()。
5、使用escapeshellarg函数处理相关参数。Escapeshellarg函数会将任何引起参数或命令结束的字符进行转义,如单引号“’”会被转义为“\’”,双引号“””会被转义为“\””,分号“;”会被转义为“\;”,这样escapeshellarg会将参数内容限制在一对单引号或双引号里面,转义参数中所包含的单引号或双引号,使其无法对当前执行进行截断,实现防范命令注入攻击的目的。
6、使用safe_mode_exec_dir执行可执行的文件路径。将php.ini文件中的safe_mode设置为On,然后将允许执行的文件放入一个目录中,并使用safe_mode_exec_dir指定这个可执行的文件路径。这样,在需要执行相应的外部程序时,程序必须在safe_mode_exec_dir指定的目录中才会允许执行,否则执行将失败。
7、参数白名单:可以在代码中或者配置文件中限定某些参数,在使用的时候匹配一下这个参数在不在白名单列表了里面,如果不在则直接显示错误提示即可。