Java代码审计-XMI注入(XXE)

2023-11-10 07:20
文章标签 java 代码 注入 审计 xxe xmi

本文主要是介绍Java代码审计-XMI注入(XXE),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 XMLDocumentBuilderFactory 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 XMLSAXReader 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 XMLSAXBuilder 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/51516220String result="";try {//SAX Read XMLSAXParserFactory factory  = SAXParserFactory.newInstance();SAXParser saxparser = factory.newSAXParser();SAXHandler handler = new SAXHandler();saxparser.parse(request.getInputStream(), handler);//为简单,没有提取子元素中的数据,只要调用parse()解析xml就已经触发xxe漏洞了//没有回显  blind xxeresult = 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 xmlreturn "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和valueStringBuffer 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方法
,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。如图所示

1663917156_632d5c64b626f3834ca91.png!small?1663917149799

使用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文件,漏洞利用成功。

1663917199_632d5c8f4ff8cfa687987.png!small?1663917192278

浏览器显示。

1663917206_632d5c967c0a6bf885991.png!small?1663917199477

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攻击

防御代码如下:

1663917238_632d5cb69e836fb0bfd07.png!small?1663917231628

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代码审计-XMI注入(XXE)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/381192

相关文章

SpringBoot应用中出现的Full GC问题的场景与解决

《SpringBoot应用中出现的FullGC问题的场景与解决》这篇文章主要为大家详细介绍了SpringBoot应用中出现的FullGC问题的场景与解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录Full GC的原理与触发条件原理触发条件对Spring Boot应用的影响示例代码优化建议结论F

springboot项目中常用的工具类和api详解

《springboot项目中常用的工具类和api详解》在SpringBoot项目中,开发者通常会依赖一些工具类和API来简化开发、提高效率,以下是一些常用的工具类及其典型应用场景,涵盖Spring原生... 目录1. Spring Framework 自带工具类(1) StringUtils(2) Coll

SpringBoot条件注解核心作用与使用场景详解

《SpringBoot条件注解核心作用与使用场景详解》SpringBoot的条件注解为开发者提供了强大的动态配置能力,理解其原理和适用场景是构建灵活、可扩展应用的关键,本文将系统梳理所有常用的条件注... 目录引言一、条件注解的核心机制二、SpringBoot内置条件注解详解1、@ConditionalOn

通过Spring层面进行事务回滚的实现

《通过Spring层面进行事务回滚的实现》本文主要介绍了通过Spring层面进行事务回滚的实现,包括声明式事务和编程式事务,具有一定的参考价值,感兴趣的可以了解一下... 目录声明式事务回滚:1. 基础注解配置2. 指定回滚异常类型3. ​不回滚特殊场景编程式事务回滚:1. ​使用 TransactionT

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Spring LDAP目录服务的使用示例

《SpringLDAP目录服务的使用示例》本文主要介绍了SpringLDAP目录服务的使用示例... 目录引言一、Spring LDAP基础二、LdapTemplate详解三、LDAP对象映射四、基本LDAP操作4.1 查询操作4.2 添加操作4.3 修改操作4.4 删除操作五、认证与授权六、高级特性与最佳

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

SpringSecurity JWT基于令牌的无状态认证实现

《SpringSecurityJWT基于令牌的无状态认证实现》SpringSecurity中实现基于JWT的无状态认证是一种常见的做法,本文就来介绍一下SpringSecurityJWT基于令牌的无... 目录引言一、JWT基本原理与结构二、Spring Security JWT依赖配置三、JWT令牌生成与

Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码

《Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码》:本文主要介绍Java中日期时间转换的多种方法,包括将Date转换为LocalD... 目录一、Date转LocalDateTime二、Date转LocalDate三、LocalDateTim

如何配置Spring Boot中的Jackson序列化

《如何配置SpringBoot中的Jackson序列化》在开发基于SpringBoot的应用程序时,Jackson是默认的JSON序列化和反序列化工具,本文将详细介绍如何在SpringBoot中配置... 目录配置Spring Boot中的Jackson序列化1. 为什么需要自定义Jackson配置?2.