Java 審計之XXE篇

nice_0e3發表於2020-09-28

Java 審計之XXE篇

0x00 前言

在以前XXE漏洞瞭解得並不多,只是有一個初步的認識和靶機裡面遇到過。下面來 深入瞭解一下該漏洞的產生和利用。

0x01 XXE漏洞

當程式在解析XML輸入時,允許引用外部實體,導致能夠引用一個外部惡意檔案,可導致執行系統命令,內網埠檢測,檔案讀取,攻擊內網服務,dos攻擊等。

在解析外部實體的過程中,XML解析器可以根據URL中指定的方案(協議)來查詢各種網路協議和服務(DNS,FTP,HTTP,SMB等)。 外部實體對於在文件中建立動態引用非常有用,這樣對引用資源所做的任何更改都會在文件中自動更新。 但是,在處理外部實體時,可以針對應用程式啟動許多攻擊。 這些攻擊包括洩露本地系統檔案,這些檔案可能包含密碼和私人使用者資料等敏感資料,或利用各種方案的網路訪問功能來操縱內部應用程式。 通過將這些攻擊與其他實現缺陷相結合,這些攻擊的範圍可以擴充套件到客戶端記憶體損壞,任意程式碼執行,甚至服務中斷,具體取決於這些攻擊的上下文。

具體利用方式參考: 一篇文章帶你深入理解漏洞之 XXE 漏洞

0x02 Java中XXE的產生

其實說白了,也還是在web應用中接受並且解析xml的時候允許引用外部的實體。web應用中需要解析的xml,需要是可控的。

那麼先來看看漏洞產生的程式碼,前面本來想著是自己去寫一個XXE的漏洞程式碼,但是發現寫的時候報各種錯,參考其他文章的程式碼,除錯半天還是報錯。所以這裡就借用JoyChou師傅開源的Java Sec Code專案上來做一個演示。

專案地址:https://github.com/JoyChou93/java-sec-code/

DocumentBuilder

DocumentBuilder類是JDK自帶的類,在該類解析產生的XXE漏洞是有回顯的。

public String DocumentBuilderVuln01(HttpServletRequest request) {
        try {
            String body = WebUtils.getRequestBody(request);
            logger.info(body);
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            StringReader sr = new StringReader(body);
            InputSource is = new InputSource(sr);
            Document document = db.parse(is);  // parse xml

            // 遍歷xml節點name和value
            StringBuilder buf = new StringBuilder();
            NodeList rootNodeList = document.getChildNodes();
            for (int i = 0; i < rootNodeList.getLength(); i++) {
                Node rootNode = rootNodeList.item(i);
                NodeList child = rootNode.getChildNodes();
                for (int j = 0; j < child.getLength(); j++) {
                    Node node = child.item(j);
                    buf.append(String.format("%s: %s\n", node.getNodeName(), node.getTextContent()));
                }
            }
            sr.close();
            return buf.toString();
        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;
        }

saxReader

saxReader是第三方的庫,該類是無回顯的

public String SAXReaderVuln(HttpServletRequest request) {
        try {
            String body = WebUtils.getRequestBody(request);
            logger.info(body);

            SAXReader reader = new SAXReader();
            // org.dom4j.Document document
            reader.read(new InputSource(new StringReader(body))); // cause xxe

        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;
        }

SAXBuilder

第三方庫

  public String SAXBuilderVuln(HttpServletRequest request) {
        try {
            String body = WebUtils.getRequestBody(request);
            logger.info(body);

            SAXBuilder builder = new SAXBuilder();
            // org.jdom2.Document document
            builder.build(new InputSource(new StringReader(body)));  // cause xxe
            return "SAXBuilder xxe vuln code";
        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;

SAXParserFactory

該類也是JDK內建的類,但他不可回顯內容,可藉助dnslog平臺

public String SAXParserVuln(HttpServletRequest request) {
        try {
            String body = WebUtils.getRequestBody(request);
            logger.info(body);

            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser parser = spf.newSAXParser();
            parser.parse(new InputSource(new StringReader(body)), new DefaultHandler());  // parse xml

            return "SAXParser xxe vuln code";
        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;
        }
    }

XMLReaderFactory

 public String xmlReaderVuln(HttpServletRequest request) {
        try {
            String body = WebUtils.getRequestBody(request);
            logger.info(body);
            XMLReader xmlReader = XMLReaderFactory.createXMLReader();
            xmlReader.parse(new InputSource(new StringReader(body)));  // parse xml
            return "xmlReader xxe vuln code";
        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;
        }

Digester

 public String DigesterVuln(HttpServletRequest request) {
        try {
            String body = WebUtils.getRequestBody(request);
            logger.info(body);

            Digester digester = new Digester();
            digester.parse(new StringReader(body));  // parse xml
        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;
        }
        return "Digester xxe vuln code";

XMLReader

public String XMLReaderVuln(HttpServletRequest request) {
        try {
            String body = WebUtils.getRequestBody(request);
            logger.info(body);

            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser saxParser = spf.newSAXParser();
            XMLReader xmlReader = saxParser.getXMLReader();
            xmlReader.parse(new InputSource(new StringReader(body)));

        } catch (Exception e) {
            logger.error(e.toString());
            return EXCEPT;
        }

        return "XMLReader xxe vuln code";
    }

修復方法

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

0x03 結尾

本文作為一個記錄文,在Java中能解析XXE的類會比較多。因為在Java中配置檔案會頻繁的使用到XML檔案或是資料傳輸。導致XXE漏洞可能會比其他語言的出現頻率高(瞎說的)。在審計的時候可以這麼檢視有沒有使用到那幾個set方法被修復掉,如果沒有那麼就可以存在XXE。當然也要檢視使用的是哪個類進行解析,有沒有回顯的情況。有回顯的話,能不能出網,能出網的話就可以藉助dnslog平臺進行回顯。

相關文章