• 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);
        }
    }
    

    image-20220302182501427

    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);
        }
    }
    

    image-20220302234235108

    执行过程为:

    • 反射获取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);
        }
    }
    

    image-20220303002556255

    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);
        }
    }
    
    

    image-20220303003331124

    这里需要注意有几点是不同于反射调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

  • 相关阅读:
    插值法——线性分段插值
    插值法——lagrange插值
    插值法——多项式插值
    方程求根——二分法
    插值法——三次样条插值
    方程求根——两种加速迭代法
    线性方程组的迭代解法——超松弛迭代法
    线性方程组的迭代解法——共轭梯度法
    线性方程组的迭代解法——最速下降法
    Essential COM学习体会
  • 原文地址:https://www.cnblogs.com/N0r4h/p/15957904.html
Copyright © 2020-2023  润新知