@TOC
0x00 前言
0x01 XML和DTD
XXE漏洞
全程为XML External Entity Injection ,也就是XML外部实体注入漏洞
。
1、什么是XML?
百度百科
可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。
简单来说,它是一种语言,表现形式类似于HTML(超文本标记语言) ,而XML和HTML的差别在于,HTML是用于展示数据和页面,而XML是为了更好的存储和传输数据。
HTML的容错能力使得格式可以不必十分规范,例如有时可能忘记闭合标签了也不会出错。而XML语法就严格很多。
所有的XML文档均由以下简单的构建模块构成:
- 元素
- 属性
- 实体
- DATA
1.1、元素
<元素名>值</元素名>
举个例子,下面代码中有两个元素,body
和message
,其中body
的值为123
,message
的值为abc
。
<body>123</body>
<message>abc</message>
1.2、属性
属性可提供有关元素的额外信息。
属性总是被置于某元素的开始标签中。属性总是以名称/值的形式成对出现的。下面的 “img” 元素拥有关于源文件的额外信息:
<img src="study.gif" />
元素的名称是 “img” 。属性的名称是 “src”。属性的值是 “study.gif” 。由于元素本身为空,它被一个 “/” 关闭。
1.3、实体
实体是用来定义普通文本的变量,在XML中的格式如下:
<元素名>&实体名;</元素名>
即&
开头,中间是名字,以 ;
结尾
那怎么理解实体呢?
简单来说,就相当于我们学C语言的时候,定义一个变量,并给该变量赋值,以后我们就通过该变量名来引用值
举个例子,我们在xml中,定义了一个变量名为<
,给它赋值为<
,那么我们使用<
的时候,就相当于用<
了。
那么为什么不直接使用<
,而用<
替代呢?很简单,因为<
和xml语法规则冲突了,解析器会把<
当作新元素的开始,举个例子:
正常来说,我们在xml中定义一个元素如下:
<body>if salary = 100 then</body>
现在我们要修改body
的值为if salary < 100 then
,难道我们要这样改?
<body>if salary < 100 then</body>
如果按照上面的改法,<
都不配对了,都不满足xml的元素格式了。
所以改成下面这个样子,就不会和语法冲突了
<body>if salary < 100 then</body>
当上面的xml被解析的时候,<
就会被替换成<
了。
XML预定义了下面五个实体引用,当文档被XML解析器解析时,实体就会被展开。
实体引用 | 字符 |
---|---|
< |
< |
> |
> |
& |
& |
" |
" |
' |
’ |
当然,最重要的一点是,我们可以使用DTD声明使用实体!!
1.4、DATA(字符数据)
可把数据理解为XML元素的开始标签与结束标签之间的文本。
除了CDATA
区段中的文本会被解析器忽略之外,XML文档中的其他文本均会被解析器解析。
所以可以把数据分成可以解析
的和不能解析
两种。
1.4.1、PCDATA
PCDATA
的意思是被解析的字符数据(parsed character data)
。
PCDATA是会被XML解析器解析的文本,文本中的标签会被当作标记来处理,而实体会被展开。
简单来说,就是当某个XML元素被解析时,其标签之间的文本也会被解析,如下:
<name> <first>Bill</first><last>Gates</last> </name>
// <name> 元素包含着另外的两个元素(first 和 last)
解析器会把它分解为像这样的子元素:
<name>
<first>Bill</first>
<last>Gates</last>
</name>
也正因为如此,如果被解析的字符数据中包含&
、<
、或者>
之类的字符,则需要使用&
、<
以及>
实体来分别代替它们。
1.4.2、CDATA
CDATA
的意思是字符数据(character data)
在XML中,指定某段内容不必被XML解析器解析时,使用<![CDATA[...]]>
。也就是说中括号中的内容,解析器不会去分析。所以其中可以包含>
、<
、'
、"
、&
这五个特殊字符。经常把一段程序代码嵌入到<![CDATA[...]]>
中。因为代码中可能包含大量的>
、<
、'
、"
这样的特殊字符。
例如在XML中声明:
<script>
<![CDATA[
if(i<10){
printf("i<10");
}
]>
</script>
2、什么是DTD?
在XML中DTD(文档类型定义) 的作用是定义XML文档的合法构建模块。它使用一系列合法的元素来 定义文档的结构。
DTD文件对当前XML文档中的节点进行了定义,这样我们配置文件之前,可通过指定的DTD对当前XML中的节点进行检查,确定XML结构和数据类型是否合法。
DTD(文档类型定义)部分,规定了文档元素里的数据类型,以及可以出现哪些元素。
简单来说,DTD就是定义了我们的XML长啥样子!
2.1、元素
在DTD中,XML的元素通过元素声明来进行声明。元素声明使用下面的语法:
<!ELEMENT 元素名 类别>
或
<!ELEMENT 元素名(子元素)>
2.2、空元素
空元素通过类别关键词EMPTY
进行声明:
<!ELEMENT element-name EMPTY>
例子如下:
DTD:
<!ELEMENT br EMPTY>
XML:
<br/>
2.3、只有PCDATA的元素
只有PCDATA的元素通过圆括号中的 #PCDATA 进行声明:
<!ELEMENT element-name (#PCDATA)>
例子如下:
<!ELEMENT from (#PCDATA)>
2.4、带有任何内容的元素
通过类别关键词ANY
声明的元素,可包含任何可解析数据的组合:
<!ELEMENT element-name ANY>
例子如下:
<!ELEMENT note ANY>
2.5、带有子元素(序列)的元素
带有一个或多个子元素的元素通过圆括号中的子元素名进行声明:
<!ELEMENT element-name (child1)>
或
<!ELEMENT element-name (child1,child2,...)>
例子如下:
<!ELEMENT note (to,from,heading,body)>
当子元素按照由逗号分隔开的序列进行声明时,这些子元素必须按照相同的顺序出现在文档中。在一个完整的声明中,子元素也必须被声明,同时子元素也可拥有子元素。"note"元素的完整声明是:
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEENT body (#PCDATA)>