初探XML External Entity Injection(XXE)

XML

什么是XML

xml是用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言
XML 指可扩展标记语言(EXtensible Markup Language)。
XML 的设计宗旨是传输数据,而不是显示数据。
XML 是 W3C 的推荐标准。
XML 不会做任何事情。XML 被设计用来结构化、存储以及传输信息。
XML 语言没有预定义的标签。

XML和HTML之间的差异

XML和HTML是为了不同的目的而设计的,XML被设计用来传输和储存数据,其焦点是数据的内容。HTML被设计用来显示数据,其焦点是数据的外观。所以总而言之,XML旨在传输和存储数据;HTML旨在显示数据。
现实生活中一些数据之间往往存在一定的关系。我们希望能在计算机中保存和处理这些数据的同时能够保存和处理他们之间的关系。XML就是为了解决这样的需求而产生数据存储格式。

XML基本格式与基本语法

基本格式

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!--xml文件的声明-->
<bookstore> <!--根元素-->
<book category="COOKING"> <!--bookstore的子元素,category为属性-->
<title>Everyday Italian</title> <!--book的子元素,lang为属性-->
<author>Giada De Laurentiis</author> <!--book的子元素-->
<year>2005</year> <!--book的子元素-->
<price>30.00</price> <!--book的子元素-->
</book> <!--book的结束-->
</bookstore> <!--bookstore的结束-->

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

称为 XML prolog ,用于声明XML文档的版本和编码,是可选的,必须放在文档开头。standalone值是yes的时候表示DTD仅用于验证文档结构,从而外部实体将被禁用,但它的默认值是no,而且有些parser会直接忽略这一项。
基本语法:
所有 XML 元素都须有关闭标签。
XML 标签对大小写敏感。
XML 必须正确地嵌套。
XML 文档必须有根元素。
XML 的属性值须加引号。
若多个字符都需要转义,则可以将这些内容存放到CDATA里面

1
<![CDATA[内容]]>

DTD

1.XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD(document type definition) 的东西控制的。
2.DTD用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)是XML文档中的几条语句,用来
说明哪些元素/属性是合法的以及元素间应当怎样嵌套/结合,也用来将一些特殊字符和可复用代码段自定义为实体

实体引用

XML元素以形如

1
<tag>foo</tag>

的标签开始和结束,如果元素内部出现如<的特殊字符,解析就会失败,为了避免这种情况,XML用实体引用(entityreference)替换特殊字符。
XML预定义五个实体引用,即用

1
&lt; &gt; &amp; &apos; &quot; 替换 < > & ' " 

实体引用可以起到类似宏定义和文件包含的效果,为了方便,我们会希望自定义实体引用,这个操作在称为 Document Type Defination的过程中进行。
Document Type Defination:DTD,即为文档类型定义

DTD的引入方式

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

0x01-内部DTD

内部DTD:使用内部的dtd文件,即将约束规则定义在xml文档中

1
<!DOCTYPE 根元素名称[元素名称]>

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0"?>
<!DOCTYPE note [<!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)><!--定义note元素有四个元素-->
<!ELEMENT to (#PCDATA)><!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)><!--定义from元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)><!--定义head元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)><!--定义body元素为”#PCDATA”类型-->
]>
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>

0x02-外部DTD

1.引用外部的dtd文件

1
<!DOCTYPE 根元素名称 STSTEM "DTD路径">

2.引用网络上的DTD文件

1
<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL">

当引入外部的DTD时,通过如下语法进行引入

1
<!DOCTYPE root-element STSTEM "filename">

示例代码

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root-element SYSTEM "test.dtd">
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>

test.dtd

1
2
3
4
<!ELEMENT to (#PCDATA)><!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)><!--定义from元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)><!--定义head元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)><!--定义body元素为”#PCDATA”类型-->

PCDATA

PCDATA的意思是被解析的字符数据。PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。被解析的字符数据不应当包含任何&,<,或者>字符需要用

1
&amp; &lt; &gt;实体来分别替换。

CDATA

CDATA意思是字符数据,CDATA 是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。

DTD元素

DTD属性

属性声明语法

1
<!ATTLIST 元素名称 属性名称 属性类型 默认值>

DTD示例

1
<!ATTLIST payment Luckey CDATA "Q">

XML示例

1
<payment Luckey="Q" />

以下是属性类型的选项

默认属性值可以使用下列值

DTD实体

实体是用于定义引用普通文本或者特殊字符的快捷方式的变量。实体引用是对于实体的引用。实体可以在内部或者外部进行声明
此时我们按照实体有无参数分类此时可以分为一般实体和参数实体

一般实体

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

引用一般实体的方法

1
&实体名称;

ps:经实验,普通实体可以在DTD中引用,可以在XML中引用,可以在声明前引用,还可以在实体声明内部引用。

参数实体的声明

1
<!ENTITY % 实体名称 "实体内容">

引用参数实体的办法

1
%实体名称

ps:经实验,参数实体只能在DTD中引用,不能在声明前引用,也不能在实体声明内部引用。DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。
此时我们也可以按照实体的使用方法进行分类,实体分为内部声明实体和引用外部实体

内部实体

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

内部实体示例代码

1
2
3
4
5
6
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY writer "Dawn">
<!ENTITY copyright "Copyright W3School.com.cn">
]>
<test>&writer;©right;</test>

外部实体

外部实体,用来引入外部资源,有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共计算机

1
2
3
<!ENTITY 实体名称 SYSTEM "URL/URI">
or
<!ENTITY 实体名称 PUBLIC "public_ID" "URI">

外部实体示例代码

1
2
3
4
5
6
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY file SYSTEM "file:///etc/passwd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
]>
<author>&file;©right;</author>

外部实体可支持http、file等协议。不同程序支持的协议不同:

XML注入

此时我们通过上面的学习已经知道了XML的作用;XML旨在传输和储存数据;那么此时我们就可以利用闭合标签来改写XML文件
简介:XML是一种数据组织存储的数据结构方式,安全的XML在用户输入生成新的数据时候应该只能允许用户接受的数据,需要过滤掉一些可以改变XML标签也就是说改变XML结构插入新功能(例如新的账户信息,等于添加了账户)的特殊输入,如果没有过滤,则可以导致XML注入攻击。
前提:1.用户能够控制数据的输入2.程序有拼凑的数据

注入示例:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<manager>
<admin id="1">
<username>admin</username>
<password>admin</password>

</admin>
<admin id="2">
<username>root</username>
<password>root</password>
</admin>
</manager>

此时如果我们输入

1
admin </password></admin><admin id="3"><name>hack</name><password>hacker</password></admin>

那么此时最终的修改结果就会变成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<manager>
<admin id="1">
<name>admin</name>
<password>admin</password>
</admin>
<admin id="2">
<username>root</username>
<password>root</password>
</admin>
<admin id="3">
<name>hack</name>
<password>hacker</password>
</admin>
</manager>

XXE(XML External Entity Injection) 全称为 XML 外部实体注入,从名字就能看出来,这是一个注入漏洞,注入的是什么?XML外部实体固然,其实我这里废话只是想强调我们的利用点是外部实体,也是提醒读者将注意力集中于外部实体中,而不要被XML中其他的一些名字相似的东西扰乱了思维盯好外部实体就行了.如果能注入外部实体并且成功解析的话,这就会大大拓宽我们XML注入的攻击面(这可能就是为什么单独说而没有说XML注入的原因吧,或许普通的 XML 注入真的太鸡肋了,现实中几乎用不到)