声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。
关注VX公粽号“信安魔方”查阅更多实战案例!
Part-01
命令注入基本知识
命令执行漏洞是指应用有时需要调用一些执行系统命令的函数,如果系统命令代码未对用户可控参数做过滤,则当用户能控制这些函数中的参数时,就可以将恶意系统命令拼接到正常命令中,从而造成命令执行攻击。下面以 Java 语言源代码为例,分析命令注入产生的原因以及修复方法。
命令执行攻击主要存在以下几个危害:继承 Web 服务程序的权限去执行系统命令或读/写文件,反弹 shell,控制整个网站甚至控制服务器,进一步实现内网渗透。
在PHP开发语言中有system()、exec()、shell_exec()、eval()、passthru()等函数可以执行系统命令。在 Java 开发语言中可以执命令的函数有 Runtime.getRuntime.exec 和ProcessBuilder.start等。其他语言有兴趣的同学可以自行学习。
Part-02
java中两种命令注入示例代码
1、ProcessBuilder 命令执行漏洞利用
Java.lang.ProcessBuilder 类用于创建操作系统进程,每个 ProcessBuilder 实例管理一个进程属性集。 start() 方法利用这些属性创建一个新的 Process 实例,可以利用ProcessBuilder 执行命令。
ProcessBuilder 执行命令的方式如下:
ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg");
Process process = pb.start();
例如,使用 ProcessBuilder 执行“cat /etc/passwd"这个指令。
public class exec {
public static void main(String[] args) throws IOException {
//执行系统命令
ProcessBuilder p = new ProcessBuilder("cat","/etc/passwd");
Process pb = p.start();
//获取执行完成命令后的结果并输出
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(pb.getInputStream(),
"GBK"));
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
}
}
Java 命令执行漏洞的前提是执行命令的参数可控,参数没有经过相关过滤。通过前面的讲解我们知道了 ProcessBuilder 进行命令执行的方法及过程,下面我们通过典型的Java 代码讲解命令执行漏洞,示例程序包首先通过“request.getParameter("ip")”获取 ip 参数传入的数据,然后利用 ProcessBuilder 进行 ping 命令的执行,最后将相关结果返回;此代码其实在日常的运维系统里边比较常见,其他系统中可能会引用较少,如果大家在遇到运维系统时,可以重点关注系统命令执行漏洞。典型漏洞代码如下:
<%
String ip=request.getParameter("ip");
try {
String exec="ping -t 3 "+ip;
ProcessBuilder p = new ProcessBuilder("bash", "-c", exec);
Process pb = p.start();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(pb.getInputStream(),
"GBK"));
while ((line = reader.readLine()) != null)
{
out.println(line);
}
reader.close();
} catch (Exception e) {
out.println(e);
}
输入“ip=127.0.0.1;id”,通过“;”进行命令拼接后发现,程序执行了 ping 和 id 两个命令,命令执行攻击成功,返回来除了ping以外的id命令执行后的结果。
2、Runtime exec 命令执行漏洞
java.lang.Runtime 公共类中的 exec()方法同样也可以执行系统命令,exec()方法在执行命令时,当利用 exec()进行命令执行时,如果参数没有经过过滤就可能通过命令拼接符进行命令拼接执行多条命令。如下图代码。
<%
String ip=request.getParameter("ip");
try {
String[] command = { "/bin/sh", "-c", "ping -t 3 " +ip};
Process proc = Runtime.getRuntime().exec(command);
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream(),
"GBK"));
while ((line = reader.readLine()) != null) {
out.println(line);
}
reader.close();
} catch (Exception e) {
out.println(e);
}
%>
因为 ip 参数没有经过过滤就直接拼接到了 command 变量中,这样就造成了命令执行漏洞,输入“ip=127.0.0.1;id”,这样就可以执行 ping 127.0.0.1 和 id 两条命令。
Part-03
命令执行审计方法及修复方法
从上述的缺陷代码中,执行命令过程中均带了特征,那就是关键字,如getRuntime()、exec、Process、ProcessBuilder等,所以审计的方法还是从关键字入手,拿到代码后,全局搜索如上关键字,找到后,重点审阅用户的入参是否具有过滤措施。
修复命令执行漏洞,可以通过以下方法:
1、检查代码是否对用户输入进行了验证,确 保输入符合预期的格式。例如,只允许字母数字字符和特定的安全字符用于文件名等输入。
2、可以使用正则表达式来验证输入。
3、使用参数化的方式来调用外部命令,而不是直接拼接命令字符串。例如,在一些数据库命令执行场景(如果涉及外部数据库命令工具调用)或者一些可以支持参数化的命令执行框架中,这可以避免命令注入