命令注入漏洞

命令注入漏洞

    • 原理
    • 示例代码
    • 命令注入的局限
    • 无法进行命令注入的原因

原理

命令注入是指在某种开发需求中,需要引入对系统本地命令的支持来完成某些特定的功能。当未对可控输入的参数进行严格的过滤时,则有可能发生命令注入。攻击者可以使用命令注入来执行系统终端命令,直接接管服务器的控制权限。

在开发过程中,开发人员可能需要对系统文件进行移动、删除或者执行一些系统命令。Java的Runtime类可以提供调用系统命令的功能。如下代码可根据用户输入的指令执行系统命令。由于cmd参数可控,用户可以在服务器上执行任意系统命令,相当于获得了服务器权限。

示例代码

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Proxy;


@WebServlet(name="Command",urlPatterns = "/Command")
public class Command extends HttpServlet {

    @Override
    public void init() throws ServletException{

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String cmd = req.getParameter("cmd");
        Process process = Runtime.getRuntime().exec(cmd);
        InputStream in = process.getInputStream();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] b = new byte[1024];
        int i = -1;
        while ((i = in.read(b))!=-1){
            byteArrayOutputStream.write(b,0,i);
        }
        PrintWriter out = resp.getWriter();
        out.print(byteArrayOutputStream.toString());
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }

    @Override
    public void destroy() {
        super.destroy();
    }
}

命令注入的执行结果如图
命令注入漏洞_第1张图片

命令注入的局限

系统命令支持使用连接符来执行多条语句,常见的连接符有|、||、&、&&,其含义为

符号 含义
| 前面命令输出结果作为后面命令的输入内容
|| 前面命令执行失败时才执行后面的命令
& 前面命令执行后继续执行后面的命令
&& 前面命令执行成功后才执行后面的命令

例如命令ping www.baidu.com&ipconfig的执行效果如图所示,先执行完ping命令,后执行ipconfig命令
命令注入漏洞_第2张图片
对于Java环境中的命令注入,连接符的使用存在一些局限。例如如下代码,利用ping命令来诊断网络。其中url参数为用户可控,当恶意用户输入www.baidu.com&ipconfig时,系统可以成功执行,但是Java运行环境中就不行,因为www.baidu.com&ipconfig被当作一个完整的字符串而非两条命令,因此如下代码不存在命令执行漏洞。

protected ByteArrayOutputStream ping(String url) throws IOException{
	Process process = Runtime.getRuntime().exec("ping " + url);
	InputStream in = process.getInputStream();
	ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
	byte[] b = new byte[1024];
	int i = -1;
	while((i = in.read(b)) != -1){
		byteArrayOutputStream.write(b,0,i);
	}
	return byteArrayOutputStream;
}

无法进行命令注入的原因

Runtime类中exec方法存在如下几种实现,显而易见,要执行的命令可以通过字符串和数组的方式传入。

public Process exec(String command) throws IOException {
        return exec(command, null, null);
    }
public Process exec(String command, String[] envp) throws IOException {
        return exec(command, envp, null);
    }
public Process exec(String cmdarray[]) throws IOException {
        return exec(cmdarray, null, null);
    }
public Process exec(String[] cmdarray, String[] envp, File dir)
        throws IOException {
        return new ProcessBuilder(cmdarray)
            .environment(envp)
            .directory(dir)
            .start();
    }

当传入的参数类型为字符串时,会先经过StringTokenizer的处理,主要是针对空格以及换行符等空白字符进行处理,后续会分割出一个cmdarray数组保存分割后的命令参数,其中cmdarray的第一个元素为所要执行的命令。经过处理后的参数www.baidu.com&ipconfig成为ping命令的参数,因此此时的连接符&并不生效,从而无法注入系统命令。

你可能感兴趣的:(Java代码审计,渗透测试,网络安全,Java代码审计)