JAVA审计-命令执行

前言

审计中最直接shell的还是rce,本篇记录下java中命令执行。

0x01 Runtime执行

public class LocalRuntime extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String cmd = req.getParameter("cmd");
        InputStream ins = Runtime.getRuntime().exec(cmd).getInputStream();
        ServletOutputStream sos = resp.getOutputStream();
        int len;
        byte[] bytes = new byte[1024];
        while ((len = ins.read(bytes))!=-1){
            sos.write(bytes, 0, len);
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}

JAVA审计-命令执行

0x02 反射Runtime执行

public class ReflactRuntime extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        String cmd = req.getParameter("cmd");
        try {
            Class cls = Class.forName("java.lang.Runtime");
            Constructor constructor = cls.getDeclaredConstructor();
            constructor.setAccessible(true);
            Object runtime = constructor.newInstance();
            Method exec = cls.getMethod("exec", String.class);
            Process process = (Process) exec.invoke(runtime, cmd);

            InputStream ins = process.getInputStream();
            int len;
            byte[] bytes = new byte[1024];
            ServletOutputStream sos = resp.getOutputStream();
            while ((len = ins.read(bytes)) != -1){
                sos.write(bytes, 0, len);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

JAVA审计-命令执行

执行过程为:

  • 反射获取Runtime的class对象

  • 获取Runtime构造方法

  • newInstance一个新Runtime的实例对象

  • 获取exec方法

  • invoke激活执行

0x03 ProcessBuilder 执行

ProcessBuilder此类用于创建操作系统进程。每个ProcessBuilder实例管理进程属性的集合。 start()方法使用这些属性创建一个新的Process实例。 start()方法可以从同一实例重复调用,以创建具有相同或相关属性的新子进程。

ProcessBuilder.start()Runtime.exec方法都可以创建一个本机进程并返回一个Process子类的Process (Runtime.exec底层调用的也是ProcessBuilder.start()),可以用来控制进程并获取有关它的信息。

public class ProccessBuilder extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        InputStream ins = new ProcessBuilder(req.getParameterValues("cmd")).start().getInputStream();
        ServletOutputStream sos = resp.getOutputStream();
        int len;
        byte[] buffer = new byte[1024];
        while ((len = ins.read(buffer)) != -1){
            sos.write(buffer,0, len);
        }

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

JAVA审计-命令执行

ProcessBuilder.start()和Runtime.exec()的一些区别:

ProcessBuilder.start() 和 Runtime.exec()传递的参数有所不同,Runtime.exec()可接受一个单独的字符串,这个字符串是通过空格来分隔可执行命令程序和参数的;也可以接受字符串数组参数。

而ProcessBuilder的构造函数是一个字符串列表或者数组。列表中第一个参数是可执行命令程序,其他的是命令行执行是需要的参数。

0x04 反射ProcessBuilder执行

@WebServlet("/reflprocessbuild")
public class reflProcessBuild extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            String arg = req.getParameter("cmd");
            List<String> cmd = Arrays.asList(arg);
            System.out.println(cmd);

            Class cls = Class.forName("java.lang.ProcessBuilder");
            Constructor constructor = cls.getConstructor(List.class);
            constructor.setAccessible(true);
            Object pb = constructor.newInstance(cmd);
            Method start = cls.getMethod("start");
            Process process  = (Process) start.invoke(pb);
            InputStream ins = process.getInputStream();

            int len;
            byte[] buffer = new byte[1024];
            ServletOutputStream os = resp.getOutputStream();
            while ((len = ins.read(buffer)) != -1){
                os.write(buffer, 0, len);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

JAVA审计-命令执行

这里需要注意有几点是不同于反射调Runtime的地方

1、首需要用List.class占位调用getConstructor(List.class)获取ProcessBuilder的有参构造。

2、传入的参数需要用Arrays.asList做一下处理,因为调的是List类型的有参构造。

总结

审计中的函数

java.lang.Runtime
java.lang.Runtime.getRuntime()
java.lang.Runtime.getRuntime().exec
getMethod().invoke()
java.lang.ProcessBuilder
java.lang.ProcessBuilder.start()
java.lang.ProcessImpl
java.lang.UNIXProcess
...

参考

https://www.cnblogs.com/CoLo/p/15240834.html

https://www.cnblogs.com/nice0e3/p/13708704.html

https://www.cnblogs.com/nice0e3/p/13494147.html

上一篇:BES2500/BES2300 ANC Designer 编写自己的上位机


下一篇:【记录】关于macOS每次都要调用source ~/.bash_profile使环境变量生效的问题