溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么解析Java反序列化漏洞

發(fā)布時間:2021-11-20 15:55:03 來源:億速云 閱讀:124 作者:柒染 欄目:網(wǎng)絡(luò)管理

怎么解析Java反序列化漏洞,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

一、基本概念

Java序列化:就是將內(nèi)存中的Java對象轉(zhuǎn)換為字節(jié)序列的過程,可以理解為對Java對象打個快照。通過序列化,可以方便將Java對象保存在內(nèi)存、文件、數(shù)據(jù)庫等媒介中,也便于在網(wǎng)絡(luò)中傳輸和共享Java對象。

Java反序列化:就是Java序列化的逆過程,將字節(jié)序列恢復(fù)為Java對象的過程。

序列化/反序列化并不是Java語言的獨有特性,像PHP、Python、Ruby等動態(tài)語言也有類似的特性。序列化/反序列化的主要目的是:

1、遠(yuǎn)程過程調(diào)用(RPC):為不同系統(tǒng)或不同進(jìn)程之間提供Java對象數(shù)據(jù)交互;

2、緩存/持久化存儲:可以將Java對象緩存或存儲到本地文件、磁盤、數(shù)據(jù)庫等媒介中;

3、會話tokens:用于HTTP cookies、HTML form表單參數(shù)、API 認(rèn)證tokens等場景的交互數(shù)據(jù)。

在Java中,序列化/反序列化操作主要由 java.io.ObjectOutputStream.writeObject(Object) 方法和 java.io.ObjectInputStream.readObject()方法實現(xiàn);在用戶代碼中,可以通過重寫上述方法實現(xiàn)自定義操作。

Java序列化數(shù)據(jù)格式

參考文檔:https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html

Java對象經(jīng)過序列化后得到的數(shù)據(jù)是個二進(jìn)制流,以固定的魔數(shù)(0xaced)和版本(0x0005)開始;在滲透測試過程中,可以以此來識別應(yīng)用系統(tǒng)中反序列化的入口點。(0xaced 0005的base64編碼以rO0AB開始,通常在Web應(yīng)用系統(tǒng)中傳輸?shù)腏ava序列化數(shù)據(jù)會經(jīng)過base64編碼)。

Java序列化數(shù)據(jù)示例:

怎么解析Java反序列化漏洞

00000000: aced 0005 7400 0d48 656c 6c6f 2c20 776f  ....t..Hello, wo
00000010: 726c 6421                                rld!

在Github上提供了Java對象序列化dump工具,可以對Java對象序列化后的數(shù)據(jù)進(jìn)行解析,具體請參考:https://github.com/NickstaDB/SerializationDumper。例如,將上述二進(jìn)制數(shù)據(jù)解析后的結(jié)果如下:

怎么解析Java反序列化漏洞

二、漏洞原理

Java反序列化漏洞產(chǎn)生的原因在于Java應(yīng)用程序接收來自用戶的序列化數(shù)據(jù)并嘗試對其進(jìn)行反序列化;如果攻擊者通過構(gòu)造惡意輸入,讓反序列化過程產(chǎn)生非預(yù)期的對象,將可能導(dǎo)致各種后果,嚴(yán)重時可能造成遠(yuǎn)程代碼執(zhí)行。

Java序列化/反序列化代碼demo

下面代碼演示將一段字符串經(jīng)序列化保存到本地文件中,然后再從文件中恢復(fù)序列化的字符串。

package orz.vuln.poc;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

//將String對象序列化后保存到data.ser文件中
public class Serialization {
    public static void main(String[] args) throws Exception {
        String text = "Hello, world!";
        
        FileOutputStream fos = new FileOutputStream("D:/data.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(text);
        oos.close();
        fos.close();
    }
}

序列化后的數(shù)據(jù):

怎么解析Java反序列化漏洞

package orz.vuln.poc;

import java.io.FileInputStream;
import java.io.ObjectInputStream;

//將data.ser文件中的數(shù)據(jù)反序列化為Java對象:
public class Deserialization {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("D:/data.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        String text = (String) ois.readObject();
        fis.close();
        ois.close();
        System.out.println(text);
    }
}

執(zhí)行結(jié)果:

怎么解析Java反序列化漏洞

在這里,可以通過修改本地文件數(shù)據(jù)控制反序列化后的字符串的值;例如,將data.ser修改如下:

00000000: aced 0005 7400 0845 7669 6c54 6578 74    ....t..EvilText

執(zhí)行反序列化代碼,結(jié)果:

怎么解析Java反序列化漏洞

更進(jìn)一步Java序列化/反序列化

在實際開發(fā)中,更多是通過實現(xiàn)Serializable接口并重寫readObject()方法對自定義類對象進(jìn)行反序列化,以完成更多操作。如下代碼示例,我們通過自定義Test類,實現(xiàn)了Serializable接口,并重寫readObject()方法,在readObject()方法中,我們自定義輸出字符串“Oops...”和彈出計算器操作。

package orz.vuln.poc;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class DemoCode {
	public static void main(String[] args) throws Exception {
		
		Test test = new Test("calc.exe");
		
		FileOutputStream fos = new FileOutputStream("D:/object.ser");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(test);
		oos.close();
		fos.close();
		
		FileInputStream fis = new FileInputStream("D:/object.ser");
		ObjectInputStream ois = new ObjectInputStream(fis);
		Test test2 = (Test) ois.readObject();
		ois.close();
	}
}

class Test implements Serializable {
	private String cmd;
	
	public Test(String cmd) {
		this.cmd = cmd;
	}
	
	//重寫readObject()方法
	private void readObject(java.io.ObjectInputStream in) throws Exception {
		in.defaultReadObject();
		System.out.println("Oops...");
		java.lang.Runtime.getRuntime().exec(cmd);//觸發(fā)代碼執(zhí)行,模擬調(diào)用鏈
	}
}

執(zhí)行結(jié)果:

怎么解析Java反序列化漏洞

怎么解析Java反序列化漏洞

調(diào)用堆棧如下:

DemoCode [Java Application]	
	orz.vuln.poc.DemoCode at localhost:53445	
		Thread [main] (Suspended (entry into method exec in Runtime))	
			Runtime.exec(String) line: 345	
			Test.readObject(ObjectInputStream) line: 38	
			NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
			NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57	
			DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
			Method.invoke(Object, Object...) line: 601	
			ObjectStreamClass.invokeReadObject(Object, ObjectInputStream) line: 1004	
			ObjectInputStream.readSerialData(Object, ObjectStreamClass) line: 1891	
			ObjectInputStream.readOrdinaryObject(boolean) line: 1796	
			ObjectInputStream.readObject0(boolean) line: 1348	
			ObjectInputStream.readObject() line: 370	
			DemoCode.main(String[]) line: 22	
	D:\Tools\Java\jdk1.7.0_21\jre\bin\javaw.exe (2021年3月17日 下午5:13:24)	

從上述結(jié)果可以看出,反序列化將調(diào)用重寫的readObject()方法,執(zhí)行了自定義的字符串輸出和彈出計算器。如果重寫的readObject()方法中可以構(gòu)造出代碼執(zhí)行利用鏈,將存在遠(yuǎn)程代碼執(zhí)行漏洞。當(dāng)然,在實際開發(fā)過程中不可能像上述代碼一樣直接在readObject()方法內(nèi)部寫上java.lang.Runtime.getRuntime().exec(cmd)這種代碼;但是也差不太多,只是實際調(diào)用鏈比較復(fù)雜,通過控制反序列化的輸入數(shù)據(jù),結(jié)合Java反射調(diào)用機(jī)制,尋找可構(gòu)建遠(yuǎn)程代碼執(zhí)行的調(diào)用鏈,動態(tài)調(diào)用java.lang.Runtime.getRuntime().exec()完成代碼執(zhí)行。

下面可以放一個JDK7u21反序列化漏洞的調(diào)用堆棧做個對比,只是調(diào)用過程更加復(fù)雜化:

orz.vuln.poc.JDK7u21Exploit at localhost:53452	
	Thread [main] (Suspended (entry into method exec in Runtime))	
		owns: TemplatesImpl  (id=46)	
		Runtime.exec(String) line: 345	
		EvilCodes.<init>() line: 17	
		NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line: not available [native method]	
		NativeConstructorAccessorImpl.newInstance(Object[]) line: 57	
		DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 45	
		Constructor<T>.newInstance(Object...) line: 525	
		Class<T>.newInstance0() line: 374	
		Class<T>.newInstance() line: 327	
		TemplatesImpl.getTransletInstance() line: 380	
		TemplatesImpl.newTransformer() line: 410	
		NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
		NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57	
		DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
		Method.invoke(Object, Object...) line: 601	
		AnnotationInvocationHandler.equalsImpl(Object) line: 197	
		AnnotationInvocationHandler.invoke(Object, Method, Object[]) line: 59	
		$Proxy0.equals(Object) line: not available	
		LinkedHashMap<K,V>(HashMap<K,V>).put(K, V) line: 475	
		LinkedHashSet<E>(HashSet<E>).readObject(ObjectInputStream) line: 309	
		NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
		NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57	
		DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
		Method.invoke(Object, Object...) line: 601	
		ObjectStreamClass.invokeReadObject(Object, ObjectInputStream) line: 1004	
		ObjectInputStream.readSerialData(Object, ObjectStreamClass) line: 1891	
		ObjectInputStream.readOrdinaryObject(boolean) line: 1796	
		ObjectInputStream.readObject0(boolean) line: 1348	
		ObjectInputStream.readObject() line: 370	
		JDK7u21Exploit.main(String[]) line: 91	

三、總結(jié)

Java反序列化漏洞的根源在于ObjectInputStream.readObject()方法在進(jìn)行反序列化時并沒有對生成的對象類型做檢測和限制,并且當(dāng)這種反序列化漏洞存在于一些公共類庫中時,將造成重大影響。例如Apache Commons Collections中實現(xiàn)的一些類可以被反序列化用來實現(xiàn)任意代碼執(zhí)行。而在WebLogic、WebSphere、JBoss、Jenkins、OpenNMS這些應(yīng)用的反序列化漏洞能夠得以利用,就是因為這些應(yīng)用中使用了Apache Commons Collections類庫。這就好像在開啟了ASLR地址隨機(jī)化防御的系統(tǒng)中,出現(xiàn)了一個加載地址固定的共享庫,或者類似于C語言中使用的鏈接庫,當(dāng)這些庫存在漏洞時,將對使用了這些庫的應(yīng)用造成重大影響。

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI