Java代码审计——XML 外部实体注入(XXE)

news2025/1/23 17:36:43

目录

前言:

(一)XML 的常见接口

1.XMLReader

2.SAXBuilder

3.SAXReader

4.SAXParserFactory

5.Digester

6.DocumentBuilderFactory

(二)XXE 漏洞审计

(三)XXE 漏洞修复

(四)小结


前言:

XXE XML 外部实体注入。当应用程序在解析 XML 输入时,在没有禁止外部实体的加载而导致加载了外部文件及代码时,就会造成 XXE 漏洞。 XXE 漏洞可以通过 file 协议或是 FTP 协议来读取文件源码,当然也可以通过 XXE 漏洞来对内网进行探测或者功击,如图 2-96 所示。漏洞危害有:任意文件读取、内网探测、攻击内网站点、命令执行、DOS 攻击等。
图 1-0 XXE 漏洞执行流程

 

(一)XML 的常见接口


想要了解 XXE 漏洞,我们首先需要知道常见的能够解析 XML 的方法,在 Java 中我
们一般用以下几种常见的接口来解析 XML 语言。

1XMLReader


        XMLReader 接口是一种通过回调读取 XML 文档的接口,其存在于公共区域中。XMLReader 接口是 XML 解析器实现 SAX2 驱动程序所必需的接口,其允许应用程序设置和查询解析器中的功能和属性、注册文档处理的事件处理程序,以及开始文档解析。当XMLReader 使用默认的解析方法并且未对 XML 进行过滤时,会出现 XXE 漏洞。
try { 
     XMLReader xmlReader = XMLReaderFactory.createXMLReader();
     xmlReader.parse(new InputSource(new StringReader(body))); 
        } catch (Exception e) { 
             return EXCEPT; 
    }

2SAXBuilder


        SAXBuilder 是一个 JDOM 解析器,其能够将路径中的 XML 文件解析为 Document 对 象。SAXBuilder 使用第三方 SAX 解析器来处理解析任务,并使用 SAXHandler 的实例侦听 SAX 事件。当 SAXBuilder 使用默认的解析方法并且未对 XML 进行过滤时,会出现XXE 漏洞
try { 
     String body = WebUtils.getRequestBody(request); 
         logger.info(body); 
     SAXBuilder builder = new SAXBuilder(); 
     // org.jdom2.Document document 
         builder.build(new InputSource(new StringReader(body))); // cause xxe 
             return "SAXBuilder xxe vuln code"; 
     } catch (Exception e) { 
             logger.error(e.toString()); 
             return EXCEPT; 
 }

3SAXReader


DOM4J dom4j.org 出品的一个开源 XML 解析包,使用起来非常简单,只要了解基本的 XML-DOM 模型,就能使用。 DOM4J / XML 文档主要依赖于 org.dom4j.io包,它有 DOMReader SAXReader 两种方式。因为使用了同一个接口,所以这两种方式的调用方法是完全一致的。同样的,在使用默认解析方法并且未对 XML 进行过滤时,其也会出现 XXE 漏洞。
try { 
     String body = WebUtils.getRequestBody(request); 
     logger.info(body); 
         SAXReader reader = new SAXReader(); 
     // org.dom4j.Document document 
         reader.read(new InputSource(new StringReader(body))); // cause xxe 
     } catch (Exception e) { 
     logger.error(e.toString()); 
         return EXCEPT; 
 }

4SAXParserFactory


SAXParserFactory 使应用程序能够配置和获取基于 SAX 的解析器以解析 XML 文档。其受保护的构造方法,可以强制使用 newInstance() 。跟上面介绍的一样,在使用默认解析方法且未对 XML 进行过滤时,其也会出现 XXE 漏洞。
try { 
         String body = WebUtils.getRequestBody(request); 
         logger.info(body); 
         SAXParserFactory spf = SAXParserFactory.newInstance(); 
         SAXParser parser = spf.newSAXParser(); 
         parser.parse(new InputSource(new StringReader(body)), new DefaultHandler()); // parse xml
         return "SAXParser xxe vuln code"; 
 } catch (Exception e) { 
         logger.error(e.toString()); 
             return EXCEPT; 
 }

5Digester


Digester 类用来将 XML 映射成 Java 类,以简化 XML 的处理。它是 Apache Commons库中的一个 jar 包: common-digester 包。一样的在默认配置下会出现 XXE 漏洞。其触发的 XXE 漏洞是没有回显的,我们一般需通过 Blind XXE 的方法来利用:
 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; 
 }

6DocumentBuilderFactory


       javax.xml.parsers 包中的 DocumentBuilderFactory 用于创建 DOM 模式的解析器对象,
DocumentBuilderFactory 是一个抽象工厂类,它不能直接实例化,但该类提供了一个
newInstance() 方法,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对
象并返回。
try { 
     String body = WebUtils.getRequestBody(request); 
     logger.info(body); 
     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     DocumentBuilder db = dbf.newDocumentBuilder(); 
     StringReader sr = new StringReader(body); 
     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(); 
         return buf.toString(); 
     }catch (Exception e) { 
         logger.error(e.toString()); 
         return EXCEPT; 
 }

(二)XXE 漏洞审计


        XXE 漏洞的审计方法和其他漏洞类似,只是搜索的关键字有所不同。这次我们采用了 GitHub 开源的 XXE 靶场: XXE-Lab 来进行审计。通过搜索 XML 的常见关键字,可以快速地对关键代码进行定位,如图 2-1  所示。
图 2-1 搜索关键代码

 

        根据搜索结果可知,使用了“DocumentBuilderFactory.newInstance() ”,因此可通过双击跟进对应代码段查看 XML 是否可控。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, 
IOException { 
     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     DocumentBuilder db; 
     String result=""; 
     try { 
             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); 
}
通过通读源码可以发现:程序首先通过“ DocumentBuilderFactory.newInstance() ”获
取一个“ DocumentBuilderFactory ”的实例,随后通过“ DocumentBuilder::parse ”来解析
通过“ request.getInputStream() ”传入的 body 内容,并返回一个 Document 实例,漏洞关
键代码如图 2-2  所示。
图 2-2 漏洞关键代码
继续跟进程序可以发现,其通过 getValueByTagName 函数获取了 username 节点的内容,并在对比数据后将其输出到页面中。也就是说,这里可以通过控制 username 的值来达到回显 XXE 的目的,如图 2-3  所示。
图 2-3 username 值可控

 

        审计到这里,我们已经清楚了漏洞的整个触发流程及原理。接下来,可以构造一个用于 XXE 漏洞审计的常见的 Payload 。常见的 XXE Payload 如下所示:
<!--?xml version="1.0" ?--> 
<!DOCTYPE replace [<!ENTITY file SYSTEM "file:///etc/passwd"> ]> 
<xxe>&file;</xxe>
        该源码中会将 username 节点的内容进行打印,因此我们只需将上面的 XXE 节点换为
username 即可被成功解析并输出, XXE 执行效果如图 2-4  所示。最终的 Payload 如下
<!--?xml version="1.0" ?--> 
<!DOCTYPE replace [<!ENTITY file SYSTEM "file:///etc/passwd"> ]> 
<user>
    <username>&file;</username>
    <password>admin</password>
</user>
图 2-4 XXE 执行效果

(三)XXE 漏洞修复


        对于 XXE 漏洞的防御比较简单,只需在使用 XML 解析器时设置其属性,禁用 DTD或者禁止使用外部实体,一般常见的修复方案如下所示:
//实例化解析类之后通常会支持三个配置
obj.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); 
obj.setFeature("http://xml.org/sax/features/external-general-entities", false); 
obj.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        当然,在使用不同的解析库时修复方案也会略有不同。值得注意的是,
DocumentBuilder builder = dbf.newDocumentBuilder(); ”这行代码需要写在 dbf.setFeature()  之后安全措施才能够生效,否则将无法防范 XXE 漏洞。以前面的实例代码为例,我们可以通过如下方法进行修复:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, 
IOException { 
     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     DocumentBuilder db; 
     String result=""; 
     try { 
         String FEATURE = null; 
         FEATURE = "http://javax.xml.XMLConstants/feature/secure-processing"; 
         dbf.setFeature(FEATURE, true); 
         FEATURE = "http://apache.org/xml/features/disallow-doctype-decl"; 
             dbf.setFeature(FEATURE, true); 
         FEATURE = "http://xml.org/sax/features/external-parameter-entities"; 
         dbf.setFeature(FEATURE, false); 
         FEATURE = "http://xml.org/sax/features/external-general-entities"; 
             dbf.setFeature(FEATURE, false);
        FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; 
             dbf.setFeature(FEATURE, false); 
             dbf.setXIncludeAware(false); 
             dbf.setExpandEntityReferences(false); 
         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); 
}

(四)小结


        为了防御 XXE 漏洞,较为有效的处理方式是开发者在不影响系统业务的前提下做好安全配置。如果系统业务需要引用外部实体,应在后端做好参数校验。
        此外,有许多第三方组件曾被爆出 XXE 漏洞(例如, Spring-data-XMLBean 、 JavaMelody 组件 XXE Apache OFBiz 、微信支付 SDK-XXE ),建议读者朋友关注这类安全问题,避免因为使用第三方组件而引入 XXE 漏洞。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/40331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MongoDB的安装

配置环境变量,将F:\MongoDB\Server\bin的路径添加到PATH环境变量中配置环境变量,将F:\MongoDB\Server\bin的路径添加到PATH环境变量中 1、下载 在安装数据库之前将所有杀毒软件、防护软件全部关闭掉 官网下载地址&#xff1a;Download MongoDB Community Server | MongoDB …

【软件测试】测试人我明明测了,生产环境还出问题?又出幺蛾子......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 测试人对于线上问题…

大数据_数据中台建设与架构

目录 一、持续让数据用起来的机制框架 二、数据中台建设方法论 三、数据中台架构 一、持续让数据用起来的机制框架 数据中台的使命就是持续让数据用起来&#xff0c;它的根本性特点就是把“数据资产”作为基础要素独立出来&#xff0c;让成为资产的数据作为生产资料融入业务…

【SVM分类】基于matlab鸽群算法优化支持向量机SVM分类【含Matlab源码 2242期】

⛄一、鸽群算法简介 基于鸽群在归巢过程中的特殊导航行为,Duan等提出了一种仿生群体智能优化算法———鸽群优化算法.在这个算法中,通过模仿鸽子在寻找目标的不同阶段使用不同导航工具这一机制,提出了2种不同的算子模型: 1)地图和指南针算子(map and compass operator).鸽子可…

ElasticSearch入门

1. ELASTICSEARCH 1、安装elastic search dokcer中安装elastic search &#xff08;1&#xff09;下载ealastic search和kibana docker pull elasticsearch:7.6.2 docker pull kibana:7.6.2&#xff08;2&#xff09;配置 mkdir -p /mydata/elasticsearch/config mkdir -p…

day01 Redis

day01 Redis 第一章 非关系型数据库的简介 第一节 技术发展线路 第二节 互联网发展所面临的问题 1. Web1.0 时代 2. Web2.0时代 3. 互联网三高问题 3.1 高并发、大流量 大型网站系统需要面对高并发(QPS)用户&#xff0c;大流量访问。Google日均PV数35亿&#xff0c;日均IP…

centos8.4下搭建 rocketmq集群部署 4.9.4

1.简单介绍 搭建rocketmq集群,nameserver至少3个节点&#xff0c;brokerserver采用2主2从同步&#xff0c;服务器资源多的&#xff0c;可以至少部署在7台服务器上&#xff0c;资源少的可以准备至少3台服务器 172.16.4.15nameserver172.16.4.16nameserver172.16.4.17nameserver…

三维种子点生长算法(以及Python递归深度问题)

前言 种子点生长算法是从一个种子点向周围的遍历图像的每个像素的图遍历算法。 通常在二维中有8邻域方法&#xff0c;三维中有6邻域与26邻域方法。 本文实现了三维种子点生长的6邻域算法。 种子点生长算法本质上是对图像的连通部分进行遍历&#xff0c;因此可以分别利用深度优…

spring initializr脚手架搭建详解

前段时间&#xff0c;我在「基于start.spring.io&#xff0c;我实现了Java脚手架定制」一文中讲述了敝司的微服务脚手架落地过程中的前世今生&#xff0c;并提到了基于 spring initializr 的搭建了 2.0 版本的脚手架。今天我打算和你分享一下这其中的实现过程与细节&#xff0c…

Vue3 如何实现一个全局搜索框

前言&#xff1a;自从学习 vue 以来&#xff0c;就对 vue 官网全局的 command K 调出全局关键词搜索这个功能心心念念。恰好最近项目也是需要实现一个全局搜索的功能&#xff0c;也正好可以正大光明的带薪学习这个功能的思路。网上的教程水平参差不齐&#xff0c;而恰好之前的…

qmake 与 配置文件

用qmake生成makefile的时候&#xff0c;背后会先执行一堆用qmake language编写的库文件&#xff08;配置文件&#xff09;&#xff0c;用于初始化一些环境相关的工作&#xff0c;为后续解析pro文件做准备。 下面是qmake解析一个新建的qt工程的pro文件背后所解析的配置文件的文件…

2022-11-27阿里云物联网平台 MICROPYTHON记录

之前写过EMQX在阿里云的云服务器上搭建流程&#xff0c;近期云服务器到期了&#xff0c;而且由于没有业务支撑短期也不打算再开云服务器了&#xff0c;但是物联网还是要用的&#xff0c;于是开了这个阿里云物联网的记录。 这个是比较详细的已有的博客记录 这个博客居然还有配套…

从ABNF读懂HTTP协议格式

定义 HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;超文本传输协议 HTML&#xff08; Hyper Text Markup Language&#xff09;超文本标记语言 URI&#xff08;Uniform Resource Identifier&#xff09;用于标识某一互联网资源名称的字符串&#xff08;uri 包括了…

自动控制原理1~3章课后练习题

1.适合于应用传递函数描述的系统是线性定常系统 2.某0型单位反馈系统的开环增益为K&#xff0c;则在 r(t)1/2*t^2 输入下&#xff0c;系统的稳态误差为 无穷 3.动态系统 0 初始条件是指 t<0 时系统的 输入、输出以及它们的各阶导数为 0 4.若二阶系统处于无阻尼状态&#…

毕业设计-opencv图像视频质量评价分析

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

二级域名配置以及nginx解析二级域名到html页面

此文章适合发布前端项目使用&#xff0c;如果想要配置二级域名到后端服务&#xff0c;可以查看这篇文章&#xff1a;nginx配置二级域名 - 简书 在阿里云上配置二级域名&#xff0c;就是添加一条记录就可以了&#xff0c;超级简单&#xff0c;不懂的可以看后面的解释说明&#…

05.深入理解JMM和Happens-Before

JMM都问啥&#xff1f; 最近沉迷P5R&#xff0c;所以写作的进度很不理想&#xff0c;但不得不说高卷杏YYDS。话不多说&#xff0c;开始今天的主题&#xff0c;JMM和Happens-Before。 关于它们的问题并不多&#xff0c;基本上只有两个&#xff1a; JMM是什么&#xff1f;详细…

[附源码]计算机毕业设计JAVA社团管理系统

[附源码]计算机毕业设计JAVA社团管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis M…

c语言实现三子棋

目录 一、三子棋玩法 二、需要实现的游戏功能 三、拆分代码 3.1游戏菜单 3.2初始化棋盘 3.2.1函数调用 3.2.2函数体实现 3.3打印棋盘 3.3.1函数调用 3.3.2函数体实现 3.4玩家下棋 3.4.1函数调用 3.4.2函数体实现 3.4.3效果展示 3.5电脑下棋 3.5.1函数调用 3.5…

强大博客搭建全过程(1)-hexo博客搭建保姆级教程

1、 前言 本人本来使用国内的开源项目solo搭建了博客&#xff0c;但感觉1核CPU2G内存的服务器&#xff0c;还是稍微有点重&#xff0c;包括服务器内还搭建了数据库。如果自己开发然后搭建&#xff0c;耗费时间又比较多&#xff0c;于是乎开始寻找轻量型的博客系统。 此时hexo…