多平台统一管理软件接口,如何实现多平台统一管理软件接口
248
2022-10-10
java反序列化原理-Demo(二)(反序列化 java)
java反序列化原理-Demo(二)
0x00 测试代码以及运行结果
测试代码:
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(); } } } }
0x01 测试代码分析
涉及到的类:
类名 | 是否继承 Serializable | 方法名 |
---|---|---|
ReflectionObject | 继承 | transform |
ReflectionChains | 继承 | execute |
ReadObject | 继承 | readObject(重写) |
注:要想产生反序列漏洞,需要重写readObjec方法
代码流程:
0x02 核心分析
通过以上代码分析看,最终需要执行的便是以下代码:
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")
0x03补充
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://freebuf.com/vuls/170344.html
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~