Java安全笔记(2)-反射执行系统命令
Runtime
Runtime中可以获取到Runtime
实例有三种方法:
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime()
private Runtime() {}
package relfectDemo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectRuntime {
public String[] cmd = new String[]{"sh", "-c", "open /System/Applications/Calculator.app"};
public void Runtime0() throws Exception{
//利用私有变量生成实例 private static Runtime currentRuntime = new Runtime();
Class clazz = Class.forName("java.lang.Runtime");
Field field = clazz.getDeclaredField("currentRuntime");
field.setAccessible(true);
Runtime runtime = (Runtime) field.get("Runtime");
Method method = clazz.getDeclaredMethod("exec", String[].class);
method.invoke(runtime, new Object[]{this.cmd});
}
public void Runtime1() throws Exception{
//利用 public static Runtime getRuntime() {
// return currentRuntime;
// }
Class clazz = Class.forName("java.lang.Runtime");
Method method = clazz.getDeclaredMethod("getRuntime");
Runtime runtime = (Runtime) method.invoke(null);
Method method1 = clazz.getDeclaredMethod("exec", String[].class);
method1.invoke(runtime, new Object[]{this.cmd});
}
public void Runtime2() throws Exception{
// 利用构造函数 private Runtime() {}
Class clazz = Class.forName("java.lang.Runtime");
Constructor constructor = clazz.getDeclaredConstructor(null);
constructor.setAccessible(true);
Runtime runtime = (Runtime) constructor.newInstance(null);
Method method = clazz.getDeclaredMethod("exec", String[].class);
method.invoke(runtime, new Object[]{this.cmd});
}
ProcessBuilder
使用constructor
初始化对象的时候,接收的参数是一个Object数组,所以需要new Object[]
强制转换:
package relfectDemo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class ReflectProcessBuilder {
public String[] cmd = new String[]{"sh", "-c", "open /System/Applications/Calculator.app"};
public void ReflectPB0() throws Exception{
Class clazz = Class.forName("java.lang.ProcessBuilder");
Constructor constructor = clazz.getConstructor(String[].class);
//newInstance接收的是一个Object数组,需要转化一下
ProcessBuilder pb = (ProcessBuilder) constructor.newInstance(new Object[]{this.cmd});
Method method1 = clazz.getDeclaredMethod("start", null);
method1.invoke(pb, null);
}
public void ReflectPB1() throws Exception{
Class clazz = Class.forName("java.lang.ProcessBuilder");
Constructor constructor = clazz.getConstructor(List.class); //当使用List类型的构造参数
//newInstance接收的是一个Object数组,需要转化一下
ProcessBuilder pb = (ProcessBuilder) constructor.newInstance(new Object[]{Arrays.asList(this.cmd)});
Method method1 = clazz.getDeclaredMethod("start", null);
method1.invoke(pb, null);
}
public static void main(String[] args) throws Exception {
ReflectProcessBuilder reflectProcessBuilder = new ReflectProcessBuilder();
// reflectProcessBuilder.ReflectPB0();
reflectProcessBuilder.ReflectPB1();
}
}
ProcessImpl
package relfectDemo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class ReflectProcessImpl {
public String[] cmd = new String[]{"sh", "-c", "open /System/Applications/Calculator.app"};
public void ReflectPI0() throws Exception{
Class clazz = Class.forName("java.lang.ProcessImpl");
Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
method.setAccessible(true);
Map<String, String> map = null;
ProcessBuilder.Redirect[] redirect = null;
String dir = ".";
//第四个参数dir不能为空,为空会失败,表示在哪个路径下执行命令
method.invoke(null, this.cmd, map, dir, redirect, true);
}
public static void main(String[] args) throws Exception{
ReflectProcessImpl reflectProcess = new ReflectProcessImpl();
reflectProcess.ReflectPI0();
}
}
ForkAndExec
可以使用ASM执行,参考su18师傅的JNDI
结论
- 反射执行命令的时候,首先需要明白如何获取实例的对象,见Runtime执行命令的三种方式
constructor
初始化对象的时候,注意参数是Object数组,使用new Object[]
强制转换