command Injection命令注入
command Injection命令注入
命令注入,是指在某些需要输入数据的位置,构造恶意代码破环原有的语句结构,而系统缺少有效的过滤,许多内容管理cms存在命令注入漏洞。
产生原因:
web前端传递参数到后台服务器上执行(特别是一些网络设备的web管理界面),由于开发者没有对输入进行严格的过滤,导致攻击者可以构造一些带有非法目的的一些命令,欺骗后台服务器执行,最终达到破坏数据,信息泄露,甚至掌控电脑的目的。
危害:
如果web应用是root权限,可以导致攻击者可以在该服务器上执行任意命令。
命令构造四种符号(windows,linux均可)
&&:代表首先执行命令a在执行命令b,但是前提条件是命令a执行正确才会执行命令b,在a执行失败的情况下不会执行b命令。所以又被称为短路运算符。
&:代表首先执行命令a在执行命令b,如果a执行失败,还是会继续执行命令b。也就是说命令b的执行不会受到命令a的干扰,在执行效率上来说“&&”更加高效。
||:代表首先执行a命令在执行b命令,如果a命令执行成功,就不会执行b命令,相反,如果a命令执行不成功,就会执行b命令。
|:直接执行后面的b命令
linux还可以:
linux系统还可以使用分号(;)同时执行多条命令
还可以使用重定向(>)在服务器中生成文件
使用(<)从准备好的文件读取命令等
127.0.0.1 & echo test >c:\1.txt 输出test,重定向保存到c盘下的文件中
(可以在服务器中写一句话木马)
low源码分析
对输入的ip没有任何的过滤,直接拼接就可以执行命令
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
//php_uname( 's' )根据参数不同获取系统的不同信息
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
根据源代码我们可以看到,对输入的ip没有作任何过滤,直接将它拼接即可执行命令,
php_uname('s')根据参数不同可以获取系统的不同信息,
stristr(string, search_string, bool)可以在string中搜索search_string 并将第一次匹配处及以后的字符串列出,如果没找到则返回false,在php中非空字符串为真,则可以判断系统类型。
没有任何过滤,直接使用 && & | || 就能完成注入
接收用户输入的ip,然后根据服务器是否是windows NT系统,对目标进行不同的ping测试
除了ping之外让他执行我的一些别的命令
php_uname 获取web操作系统(服务器)的类型,返回运行php的操作系统的相关描述,参数mode可取值"a"(此为默认,包含序列“s,n,r,v,m"里的所有模式),"s" (返回操作系统的名称),"n" (返回主机名),"r"(返回版本名称),”r"(返回版本信息),"m"(返回机器类型)
stristr()在一个字符串里找是否存在指定的字符串
stristr( php_uname( 's' ), 'Windows NT' )
就是检查web服务器是不是windows服务器
$cmd = shell_exec( 'ping ' . $target );
如果判断正确,是windows服务器,就给cmd赋值
shell_exec()命令执行函数,引起命令执行漏洞的原因
这个函数让php的网页程序,去执行操作系统的命令,对命令也没有过滤
ping是操作系统的命令
执行 ping 空格 我们输入的ip
结果存储在变量cmd中,echo输出结果
如果判断错误,就是linux,linux和windows的ping命令不同,
windows是发4个包,linux是一直发包
ping -c 4 指定发包次数
检查web服务器操作系统类型,根据不同情况,执行不同操作系统命令、
拼接之后就是,
ping 127.0.0.1 | net user
不需要闭合什么的,能够同时执行多条命令就可以
利用(用命令行获取管理员权限)
127.0.0.1 | net user
127.0.0.1 | net user test 123/add
添加账号
127.0.0.1 | net localgroup administrators test /add
添加管理员权限
ping 192.168.225.1 主机
192.168.225.1&dir
dir命令类似于ls
显示一个磁盘上全部或部分文件目录(文件或文件夹),并显示文件信息(文件名,拓展名,文件长度,文件建立,最好一次修改的日期和时间等,不显示文件具体内容)
127.0.0.1&ipconfig
127.0.0.1 & net user xie /add 创建用户
127.0.0.1 & net 查看系统用户
medium级别命令注入漏洞
$substitutions = array(
'&&' => '',
';' => '',
);
//数组定义一堆变量,变量&&,值为空
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
array_keys( $substitutions )要替换的内容
array_keys()获取数组(变量$substitutions)的键值,也就是&& ; 获取变量的key
获取之后,替换成$substiutions,也就是括号中第二个,变量的值''
$substitutions替换之后的内容
$target我们输入的内容
就是用一个数组做的,两个str_replace
应对方法
使用其他连接符,比如 &
利用黑名单漏洞 127.0.0.1&;&net user
high
$target = trim($_REQUEST[ 'ip' ]);
去掉字符串头尾空格
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
把target的ip地址,用点来分割,分割之后变成四个变量,放入一个数组中
is_number($octet[0])判断octet这个数组第一个变量是不是数字
这四个变量都要是数字
还要判断
sizeof($octet)==4 判断这个变量数是不是4
四个变量重新拼接
high级别黑名单范围很全,但还是遗漏了一些连接符,可以利用 空格+|(管道符前一个命令的输出作为后一个命令的输入,且只能打印后面命令的结果)
源代码是过滤了 |+空格
也可以使用aaaa |net user
使用一个不会执行的命令和|来执行命令
漏洞分析
不具有通用性,只能防止ping命令
定义白名单,只允许输入ip地址
linux可以用第二种方法,给php建立独立的账号
漏洞防御:
在low的源代码中添加,escapeshellcmd()函数,对一些能引起命令执行漏洞的符号进行转义
escapeshellarg()把输入的命令变成一个整体,去ping
impossible
源码改动如下,可以发现加入了Anti-CSRF token,同时他将输入的命令通过stripslashes去掉反斜杠,由于规则是要输入ip地址,所以根据.来将输入的命令分成四个数组,之后通过is_numeric判断每个数组是否为数字且是否只有四个数组,判断成功后,按固定的ip格式重新组合地址,达到严格的参数限制,只有num.num.num.num才能执行。利用参数化的方式很好的避免了黑名单考虑不全和容易绕过的缺陷,防止了命令注入。
stripslashes(string) : 该函数会删除字符串string中的反斜杠,返回已剥离反斜杠的字符串。
explode(separator,string,limit): 该函数把字符串打散为数组,返回字符串的数组。参数separator规定在哪里分割字符串,参数string是要分割的字符串,可选参数limit规定所返回的数组元素的数目。
is_numeric(string): 该检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE。
可以看到,Impossible级别的代码加入了Anti-CSRF token,同时对参数ip进行了严格的限制,只有诸如“数字.数字.数字.数字”的输入才会被接收执行,因此不存在命令注入漏洞。