XML 基础知识 && XXE 漏洞原理解析及实验
XML 介绍
XXE
全称XML
外部实体注入,所以在介绍XXE
漏洞之前,先来说一说什么是XML
以及为什么使用XML
进而再介绍一下XML
的结构。
XML
全称 可拓展标记语言,与HTML
相互配合后:
HMTL
用来显示数据HTML
的焦点在于数据的外观(如何显示数据)XML
用来传输和存储数据XML
的焦点在于数据的内容(如何存储传输数据)
总结来说:HTML
提供了一个模板,XML
动态的改变模板中对应数据位置中的数据。
为什么要将数据从 HTML 中分离
若要在HTML
文档中显示动态的数据,每当数据需要改变的时候需要大量的时间编辑HTML。
通过XML
将数据存储在独立的XML
文件中,每次需要更新数据时只需通过发出XMLHttpRequest
到服务端请求相应的数据(Ajax
)即可。
而HTML/CSS
只需专注于显示与布局即可,底层的数据从XML
文件中获取即可,这样修改底层的数据不会对HTML
的结构发生任何改变。
XML 的其他优点
XML
不仅可以用于简化HTML
的数据传输于存储中,所有支持XML
格式的应用都可以从XML
文件中读取文件来使用。而且
XML
提供了一种数据的格式标准,所有支持该标准的应用之间都可以用该格式在本地或网络中传输数据。XML
可自定义标签,XML
是没有预定义标签的。
XML DTD
既然前面说了XML
是没有预定义标签的,也就是说无论想定义什么名字的标签都可以,这个标签有什么属性都可以,看似很自由,但在开发中显然是不合适的,而且在数据的传输过程中如果双方的XML
结构不同也会出现问题,所以需要一个东西来约束XML
的格式,也就是DTD
(文档类型定义)
所以通过DTD
有如下优势:
每一个
XML
文件均可携带一个有关其自身格式的描述,从而规范XML
的结构一个通信过程中,可一致地使用规定的
DTD
来交换数据应用程序也可使用规定的
DTD
来验证从外部接收到的或自身的数据
如何定义 DTD
一般有两种方式:
内部
DOCTYPE
声明外部文档声明(!!理解
XXE
的关键!!)
DTD
(文档类型定义)被包装在DOCTYPE
声明中 (无论外部还是内部)。
内部 DOCTYPE 声明
利用DOCTYPE
声明内部DTD
的格式为:
<!DOCTYPE root-element [element-declarations]>
root-element
文档类型(根元素)[element-declarations]
其余的元素都包含在[ ]
中
<!--xml声明--><?xml version="1.0" encoding="utf-8" ?><!--文档类型定义--><!DOCTYPE note [ <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> ]><!--文档元素--><note> <to>XXE</to> <from>LEARING</from> <heading>hello</heading> <body>My_friend</body></note>
<!DOCTYPE note [
规定该文档是 note 类型的文档 (根元素为<note>
)对应
<note> </note>
<!ELEMENT note (to,from,heading,body)>
定义note
中有四个元素,分别为:<to> </to>
<from> </from>
<heading> </heading>
<body> </body>
<!ELEMENT to (#PCDATA)>
定义to
元素为#PCDATA
类型其他的类似
#PCDATA
表示名字里面可以放任意文本 - 这不是我们关注的重点。
外部文档声明( important )
若DTD
位于XML
源文件的外部,则可以通过如下语法将其封装声明在DOCTYPE
中
<!DOCTYPE root-element SYSTEM "filename">
记得该语法,XXE
中会用到。
我们将这个外部的DTD
文件命名为note.dtd
:
<!ELEMENT note (to,from,heading,body)><!ELEMENT to (#PCDATA)><!ELEMENT from (#PCDATA)><!ELEMENT heading (#PCDATA)><!ELEMENT body (#PCDATA)>
此时若是想在XML
文件中声明该DTD
约束,应声明为:
<!--xml声明--><?xml version="1.0" encoding="utf-8" ?><!-- 外部引入 dtd 文件 --><!DOCTYPE note SYSTEM "note.dtd"><!--文档元素--><note> <to>XXE</to> <from>LEARING</from> <heading>hello</heading> <body>My_friend</body></note>
此时便会引入上述note.dtdDTD
约束文件,
而这个引入的文件,就是该漏洞的关键之一。
DTD - 实体
实体是用于定义XML
文档中特殊字符的快捷方式,就类似于一个变量或一个宏(宏可能更好理解)。
内部实体
在DTD
中声明实体,则称为内部实体
<!ENTITY entity-name "entity-value">
entity_name
是实体的名称,后跟双引号或单引号中的值entity_value
保存实体名称的值
同样是上面的例子,还可以定义成这样:
<!--xml声明--><?xml version="1.0" encoding="utf-8" ?><!--文档类型定义--><!DOCTYPE note [ <!ELEMENT note (#PCDATA)> <!ELEMENT to "XXE"> <!ELEMENT from "LEARING"> <!ELEMENT heading "hello"> <!ELEMENT body "my_friend"> ]><!-- 一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (;) --><note> &to; &from; &heading; &body;</note>
在上面的示例中,各个实体名称tofromheadingbody
由它们在声明中的值替换。通过向实体名称添加前缀&
来取消引用实体值。
外部实体
如果在DTD
之外声明实体,则称为外部实体。
<!ENTITY name SYSTEM "URI/URL">
name
实体的名称SYSTEM
关键字URI/URL
是双引号或单引号中包含的外部源的地址
<!ENTITY writer SYSTEM "<http://www.shtwo.com/note.dtd>">
使用的方式与上述例子相同,只不过当前是从外部引入,可以是一个URL
链接中的文件,也可以是本地的文件(这也就造成了安全的风险)。
可以使用 系统标识符或 公共标识符来引用外部实体:
系统标识符
系统标识符可以指定包含
DTD
声明的外部文件的位置:它包含关键字SYSTEM
和指向文档位置的URI
引用<!DOCTYPE name SYSTEM "note.dtd" [...]>
是不是很熟悉公共标识符
<!DOCTYPE name PUBLIC "-//Beginning XML//DTD Address Example//EN">
XXE - XML 外部实体注入
利用 XXE 外部实体获取文件 - 有回显
通过刚才的介绍,可以明显看出若允许外部文档的声明,那么若请求放的 XML 数据可以被我们控制,就可以在其中加入一个用于包含目标机器本地文件的一个外部文档声明,并回显回来。
但注意,对于有回显的XXE
要满足这样几个条件:
必须存在使用
XML
传输数据的情况,且传输的数据我们可以控制;通过外部文档声明的外部实体要放在一个可以回显到当前页面中的位置,这样被恶意读取的数据才返回显示给我们。
看了这些可能有点不太理解,下面以Vulnhub
打靶过程中,一个环节存在的XXE
漏洞为例:
Vulnhub - 打靶示例
当前访问到一个注册的页面,让输入个人信息并进行注册,所以我们打开Burp
提交数据进行抓包。
在抓到的 POST 请求包中,可以明显看出当前我们注册填写的信息就是通过 XML 形式提交的,所以满足了上面说的第一个条件:必须存在使用XML
传输数据的情况,且传输的数据我们可以控制。
且根据不断地尝试,发现无论email
处填写什么,都会有is not available
的提示,但仔细看,当提交的email
不同时,返回的错误提示信息中的邮箱也会变化,也就是说明我们在<email> </email>
中提交的数据会被原封不动的拼接到Sorry, xxxxx is not available!!
语句中xxxxx
的部分,并返回来,这也就满足了上述说的第二个条件:通过外部文档声明的外部实体要放在一个可以回显到当前页面中的位置,这样才能被看到。
所以此时就可以尝试XXE
了:
插入一个外部文档引用的声明,通过SYSTEM
读取一个外部的位于Linux
主机上的文件,并将引入的文档赋予deu
这个实体(这个名字随便起)
<!DOCTYPE foo [<!ENTITY deu SYSTEM 'file:////etc/passwd'>]>
并且要在<email> </email>
中引用该外部实体deu
<!DOCTYPE foo [<!ENTITY deu SYSTEM 'file:////etc/passwd'>]><email>&deu;</email>
这就完成了一个XML
外部实体注入 -XXE
什么?还不太理解,那再与XSS
对比来说一下XXE
的特征
XXE 与 XSS 的异同
XSS
判断的条件一般是:通过浏览器(表单/变量)提交一个数据到服务器端,服务器端没有做任何变化过滤,就直接将我们输入的数据原封不动的返回到页面中。XSS
的攻击目标大多数是浏览器端XXE
判断的条件一般是:和XSS
有些类似,也是通过浏览器(表单/变量)提交一个数据到服务器端,服务器端没有做任何变化过滤,就直接将我们要引用的服务器端的资源原封不动的返回到页面中。XXE
攻击的对象是服务器端
portswigger - XXE 靶场 - 1
再以 Burp 官网提供的第一个XXE
的题为例:
网址: https://portswigger.net/web-security/xxe/lab-exploiting-xxe-to-retrieve-files
流程一致,我们要找到可能存在数据交互的位置,这样才有存在 XXE 的可能,所以一上来先点 Home 试了以下,看看有没有登录的界面,发现并没有,于是随便点开一个商品View details
在其中看到了一个Check stock
好像是一个提交数据的位置,于是打开Burp
进行抓包。
果然是XML
数据的格式,这次也懒得在判断在哪个位置可以回显,直接扔进Repeater
在每一个XML
的标签中都放上我们声明的外部实体,果然会显出了/etc/passwd
利用 XXE 外部实体获取文件 - 无回显
直接用实验说明
通过 DNSlog 回显数据
可以看到本事的要求是确定 目标服务器是否存在 无回显的XXE
而确认的方式就是通过DNSlog
看是否有DNS
或HTTP
请求到来,但处于安全性原因不允许使用自己搭建的或外部的DNSlog
服务器,要使用Burp
中自带的由官方架设于默认公共服务器上的DNSlog
服务器。
其在Burp
的位置是:
进入后点击Copy to clipboard
生成一个子域名,接下来无论是通过DNS
查询该子域名 还是通过HTTP
范围该域名都会在下面的Poll Collaborator interactions
中显示请求。
不过首先还是按常规的方式来测试一下XXE
按照之前的套路,这次并没有返回/etc/passwd
的内容,只是返回了 Invalid product ID
的提示,所以此时还不能判断存在XXE
漏洞(不能判断我们写的外部文档声明起作用了)。
为了进一步,确认到底是不存在XXE
还是只是没有回显,此时将对我们自己定义的外部文档声明中的实体引用改为一个错误的变量名。
<storeID>
&de;
</sroreID>
此时出现了有关XML
解析错误的报错,说明若是XML
解析失败是会单独报错的,所以大概率可以确认之前的语句已经被成功执行了,只不过没有回显。
由于没有回显,为了进一步确认到底是否存在 无回显的XXE
此时将外部文档声明中所引入的外部文件指向各个生成的那个域名。
之后果然在本地看到了目标对 刚刚传入域名的DNS
请求与HTTP
请求。
利用 XXE 执行 SSRF 攻击
在刚刚基础中,介绍外部实体时,举了一个这样的例子:
<!ENTITY writer SYSTEM "<http://www.shtwo.com/note.dtd>">
不难发现,这后面明显包含的是一个URL
,所以若将这部分换为一个内网的IP
貌似也没问题喔,所以就有可能造成SSRF
及时我们不知道内网的IP
,若存在SSRF
也可以通过 在XXE
中附加可能的内网IP
对内网的资源进行一个探测。
Portswigger - XXE 靶场 - 2
网址:https://portswigger.net/web-security/xxe/lab-exploiting-xxe-to-perform-ssrf
该靶场只能说非常的贴心啊 ... 连存在敏感信息的IP
都给我们了。
那就直接开始吧,首先还是要找存在XML
信息交互的位置,该题遇上一道的位置相同,所以就略过了,直接写入外部文档声明
<!DOCTYPE foo [<!ENTITY deu SYSTEM "<http://169.254.169.254>">]>
得到了一个目录,再继续向下遍历:
最终成功获得到敏感信息:
由于最难的一步找到要攻击目标这一步被直接告诉了,所以很简单就找到了敏感的信息。
防御方式
禁用外部实体(大多数都采用该方法)
PHP
中libxml_disable_entity_loader(true);
黑名单过滤(不安全)
项目地址
Lab: Exploiting XXE to perform SSRF attacks | Web Security Academy
https://github.com/shungli923/WowBigBug/blob/main/
直链地址下载
https://lp.lmboke.com/WowBigBug-main.zip
有趣的 Youtuber
Seven Seas Security
XXE 相关实验环境
https://pentesterlab.com/exercises/play_xxe/course
免责声明
本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本平台和发布者不为此承担任何责任。