您好,登錄后才能下訂單哦!
測試代碼:
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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。