1 XML 注入攻击
1.1 XML漏洞攻击原理
1.1.1 什么是XML
XML 指可扩展标记语言(EXtensible Markup Language)。
XML 是一种很像HTML的标记语言。
XML 的设计宗旨是传输数据,而不是显示数据。
XML 标签没有被预定义。您需要自行定义标签。
XML 被设计为具有自我描述性。
XML 是 W3C 的推荐标准。
1.1.2 XML注入漏洞原理
使用不可信数据来构造XML会导致XML注入漏洞也成称为XXE漏洞。一个用户,如果他被允许输入结构化的XML片段,且输入的片段未做任何防御措施,则他可以在XML的数据域中注入XML标签来改写目标XML文档的结构与内容。XML解析器会对注入的标签进行识别和解释。
1.2 XML注入基础知识
1.2.1 DTD
首先先来了解一下DTD含义。DTD(文档类型定义,Document Type Definition)的作用是定义 XML
文档的合法构建模块。它使用一系列的合法元素来定义文档结构。DTD可被成行的声明于XML文档中,也可作为一个外部引用
1.2.2 实体ENTITY
XML中的实体类型,一般有下面几种:字符实体、命名实体(或内部实体)、外部普通实体、外部参数实体。除外部参数实体外,其它实体都以字符(&)开始,以字符(;)结束。
- 字符实体
字符实体类似html中的实体编码,形如:a(十进制)或者a(十六进制)。
- 命名实体(内部实体)
内部实体又称为命名实体。命名实体可以说成是变量声明,命名实体只能声明在DTD或者XML文件开始部分(<!DOCTYPE>语句中)。
命名实体(或内部实体)语法:
<!ENTITY 实体名称 “实体的值”>
如:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY x "xxe1">
<!ENTITY y "xxe2">
]>
<root><x>&x;</x><y>&y;</y></root>
定义实体名称x和y 值为xxe1和xxe2!
&x; 引用实体x;&y引用实体y
- 外部普通实体
外部实体用于加载外部文件的内容。(显式XXE攻击主要利用外部普通实体)
外部普通实体语法:
<!ENTITY 实体名称 SYSTEM "URI/URL">
如:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPe root [
<!ENTITY outfile SYSTEM "outfile.xml">
]>
<root><outfile>&outfile;</outfile></root>
- 外部参数实体
参数实体用于DTD和文档的内部子集中。与一般实体不同,是以字符(%)开始,以字符(;)结束。只有在DTD文件中才能在参数实体声明的时候引用其他实体。(Blind
XXE攻击常利用参数实体进行数据回显)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % p1"hello">
<!ENTITY % p2 " ">
<!ENTITY % p3 "jj">
<!ENTITY dtd SYSTEM "combine.dtd">
%dtd;
]>
<root><foo>&content</foo></root>
combine.dtd中的内容为:
<!ENTITY content "%param1;%param2;%param3;">
上面combine.dtd中定义了一个基本实体,引用了3个参数实体:%p1;,%p2;,%p3;。
解析后…中的内容为hello jj。
1.3 XML注入审计函数
一般在传输数据接口和导入配置等场景可能会用到XML解析,若涉及到XML文件处理的场景要查看是否禁用DTD外部实体,来判断是否存在XXE。常用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
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
1.4 XML注入漏洞危害
读取任意文件
执行系统命令
探查内网端口
攻击内网网站
1.5 XML注入漏洞代码示例
1.5.1 DocumentBuilder ( ** DOM Read XML** )
DocumentBuilder类是JDK自带的类,在该类解析产生的XXE漏洞是有回显的。
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String result="";
try {
//DOM Read XML
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(request.getInputStream());
String username = getValueByTagName(doc,"username");
String password = getValueByTagName(doc,"password");
if(username.equals(USERNAME) && password.equals(PASSWORD)){
result = String.format("<result><code>%d</code><msg>%s</msg></result>",1,username);
}else{
result = String.format("<result><code>%d</code><msg>%s</msg></result>",0,username);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
result = String.format("<result><code>%d</code><msg>%s</msg></result>",3,e.getMessage());
} catch (SAXException e) {
e.printStackTrace();
result = String.format("<result><code>%d</code><msg>%s</msg></result>",3,e.getMessage());
}
response.setContentType("text/xml;charset=UTF-8");
response.getWriter().append(result);
}
1.5.2 saxReader ( DOM4J Read XML )
saxReader是第三方的库,该类是无回显的
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String result="";
try {
//DOM4J Read XML
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(request.getInputStream());
String username = getValueByTagName2(document,"username");
String password = getValueByTagName2(document,"password");
if(username.equals(USERNAME) && password.equals(PASSWORD)){
result = String.format("<result><code>%d</code><msg>%s</msg></result>",1,username);
}else{
result = String.format("<result><code>%d</code><msg>%s</msg></result>",0,username);
}
} catch (DocumentException e) {
System.out.println(e.getMessage());
}
response.setContentType("text/xml;charset=UTF-8");
response.getWriter().append(result);
}
1.5.3 SAXBuilder ( ** JDOM2 Read XML** )
无回显
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String result="";
try {
//JDOM2 Read XML
SAXBuilder builder = new SAXBuilder();
Document document = builder.build(request.getInputStream());
String username = getValueByTagName3(document,"username");
String password = getValueByTagName3(document,"password");
if(username.equals(USERNAME) && password.equals(PASSWORD)){
result = String.format("<result><code>%d</code><msg>%s</msg></result>",1,username);
}else{
result = String.format("<result><code>%d</code><msg>%s</msg></result>",0,username);
}
} catch (JDOMException e) {
System.out.println(e.getMessage());
}
response.setContentType("text/xml;charset=UTF-8");
response.getWriter().append(result);
}
1.5.4 SAXParserFactory
该类也是JDK内置的类,但他不可回显内容,可借助dnslog平台
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//https://blog.csdn.net/u011024652/article/details/51516220
String result="";
try {
//SAX Read XML
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxparser = factory.newSAXParser();
SAXHandler handler = new SAXHandler();
saxparser.parse(request.getInputStream(), handler);
//为简单,没有提取子元素中的数据,只要调用parse()解析xml就已经触发xxe漏洞了
//没有回显 blind xxe
result = String.format("<result><code>%d</code><msg>%s</msg></result>",0,1);
} catch (ParserConfigurationException e) {
e.printStackTrace();
result = String.format("<result><code>%d</code><msg>%s</msg></result>",3,e.getMessage());
} catch (SAXException e) {
e.printStackTrace();
result = String.format("<result><code>%d</code><msg>%s</msg></result>",3,e.getMessage());
}
response.setContentType("text/xml;charset=UTF-8");
response.getWriter().append(result);
}
1.5.5 XMLReaderFactory
public String xmlReaderVuln(HttpServletRequest request) {
try {
String body = WebUtils.getRequestBody(request);
logger.info(body);
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.parse(new InputSource(new StringReader(body))); // parse xml
return "xmlReader xxe vuln code";
} catch (Exception e) {
logger.error(e.toString());
return EXCEPT;
}
1.5.6 Digester
public String DigesterVuln(HttpServletRequest request) {
try {
String body = WebUtils.getRequestBody(request);
logger.info(body);
Digester digester = new Digester();
digester.parse(new StringReader(body)); // parse xml
} catch (Exception e) {
logger.error(e.toString());
return EXCEPT;
}
return "Digester xxe vuln code";
1.5.7 XMLReader
public String XMLReaderVuln(HttpServletRequest request) {
try {
String body = WebUtils.getRequestBody(request);
logger.info(body);
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
xmlReader.parse(new InputSource(new StringReader(body)));
} catch (Exception e) {
logger.error(e.toString());
return EXCEPT;
}
return "XMLReader xxe vuln code";
}
1.6 XML注入实战案例
这里借用JOYChou老师的Java Sec Code项目做一个演示。
存在漏洞代码示例:
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";
}
}
上述代码示例中的漏洞爆发行为 Document document =
db.parse(is),参数“is”直接从request中获取为用户可控参数,且未做任何过滤措施,直接进行解析,造成了XXE漏洞
要想清楚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方法
,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。如图所示
使用Burp进行抓包验证,将Content-Type: application/x-www-form-urlencoded修改成Content-Type:
application/xml,输入payload进行文件读取。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE joychou [
<!ENTITY xxe SYSTEM "file:///d://1.txt">
]>
<root>&xxe;</root>
可成功读取xml文件,漏洞利用成功。
浏览器显示。
1.7 XML注入漏洞防御
使用XML解析器时需要设置其属性,禁用DTDs或者禁止使用外部实体。
以上例中DOM – DocumentBuilderFactory为例,防御代码如下:
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); //禁用DTDs (doctypes),几乎可以防御所有xml实体攻击
//如果不能禁用DTDs,可以使用下两项,必须两项同时存在
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); //防止外部普通实体POC 攻击
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); //防止外部参数实体POC攻击
防御代码如下:
Bhnr3v-1675647810068)]
1.7 XML注入漏洞防御
使用XML解析器时需要设置其属性,禁用DTDs或者禁止使用外部实体。
以上例中DOM – DocumentBuilderFactory为例,防御代码如下:
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); //禁用DTDs (doctypes),几乎可以防御所有xml实体攻击
//如果不能禁用DTDs,可以使用下两项,必须两项同时存在
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); //防止外部普通实体POC 攻击
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); //防止外部参数实体POC攻击
防御代码如下:
[外链图片转存中…(img-RgQn0mZQ-1675647810068)]
最后
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
同时每个成长路线对应的板块都有配套的视频提供:
当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。
因篇幅有限,仅展示部分资料,有需要的小伙伴,可以【扫下方二维码】免费领取:
今天的文章java源代码审计_代码审计流程分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/85411.html