Loading

Java命令执行

Java的命令执行方式

JDK中提供的可执行系统命令的API有:

  • java.lang.Runtime
  • java.lang.ProcessBuilder
  • java.lang.UNIXProcess(Linux) / java.lang.ProcessImpl(Windows)

java.lang.Runtime

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class Test1 {
    public static void main(String[] args) throws IOException {
        try {
            String RuntimeExecRes = RuntimeTest();
            System.out.println(RuntimeExecRes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String RuntimeTest() throws IOException {
        //执行whoami命令
        InputStream ins = Runtime.getRuntime().exec("whoami").getInputStream();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int size;
        while ((size = ins.read(bytes)) > 0) {
            bos.write(bytes, 0, size);
        }

        return bos.toString();
    }
}

exec()有多种重载,传入的命令参数可以是字符串或字符串数组,实际是调用ProcessBuilderstart()方法。
image

java.lang.ProcessBuilder

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class Test2 {
    public static void main(String[] args) {
        String ProcessExecRes = null;
        try {
            ProcessExecRes = ProcessTest();
            System.out.println(ProcessExecRes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String ProcessTest() throws IOException {
        String[] cmds = {"cmd", "/c", "whoami"};
        InputStream ins = new ProcessBuilder(cmds).start().getInputStream();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int size;
        while ((size = ins.read(bytes)) > 0) {
            bos.write(bytes, 0, size);
        }
        return bos.toString();
    }
}

ProcessBuilderstart()方法实际调用的是ProcessImpl.start()方法(在Windows下)。
image

java.lang.ProcessImpl

ProcessImpl是最终调用native方法执行系统命令的类。

public class Test3 {
    public static void main(String[] args) {
        try {
            String ProcessImplRes = ProcessImplTest();
            System.out.println(ProcessImplRes);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static String ProcessImplTest() throws Exception {
        String[] cmds = {"whoami"};
        Class clazz = Class.forName("java.lang.ProcessImpl");
        Method method = clazz.getDeclaredMethod("start", new String[]{}.getClass(),
                Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
        method.setAccessible(true);
        InputStream ins = ((Process) method.invoke(null, cmds, null, ".", null, true)).getInputStream();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int size;
        while ((size = ins.read(bytes)) > 0) {
            bos.write(bytes, 0, size);
        }
        return bos.toString();
    }
}

注:在JDK17会报错:

java.lang.reflect.InaccessibleObjectException: Unable to make static java.lang.Process java.lang.ProcessImpl.start(java.lang.String[],java.util.Map,java.lang.String,java.lang.ProcessBuilder$Redirect[],boolean) throws java.io.IOException accessible: module java.base does not "opens java.lang" to unnamed module @41629346

需要添加JVM参数:--add-opens java.base/java.lang=ALL-UNNAMED

防御

  • 配置SecurityManager规则。
  • RASP

未完待续……

posted @ 2023-05-20 10:39  KRDecad3  阅读(266)  评论(0编辑  收藏  举报