从XML到XXE
XML
什么是XML?
XML指可扩展标记语言(EXtensible Markup Language)
XML的设计宗旨是传输数据,而不是显示数据
XML不会做任何事情,XML被设计用来结构化、存储以及传输信息
XML语言没有预定义的标签
XML 不是 HTML 的替代
- XML被设计用来传输和存储数据,其焦点是数据的内容
- HTML被设计用来显示数据,其焦点是数据的外观
- HTML旨在显示信息,而XML旨在传输信息
XML语法结构
语法
- XML元素都须有关闭标签
- XML标签对大小写敏感
- XML必须正确地嵌套
- XML文档必须有根元素
- XML的属性值须加引号
结构
- XML文档声明,在文档的第一行
- XML文档类型定义,即DTD,XXE 漏洞所在的地方
- XML文档元素
DTD
XML文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD(document type definition) 的东西控制的
DTD用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)
DTD文档
1 | 1.内部DTD文档 |
实体引用
XML元素以形如 <tag>foo</tag>
的标签开始和结束,如果元素内部出现如<
的特殊字符,解析就会失败,为了避免这种情况,XML用实体引用(entity reference)替换特殊字符。XML预定义五个实体引用:
1 | < < 小于号 |
DTD实体
实体是用于定义引用普通文本或特殊字符的快捷方式的变量
实体引用是对实体的引用
实体可在内部或外部进行声明
内部实体
1 | <!ENTITY 实体名称 "实体的值"> |
外部实体
1 | 有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共计算机, |
%xxe
执行后会加载外部实体 evil.dtd
并执行,得到的结果会放在中
XML注入
什么是XML注入?
XML注入攻击和SQL注入攻击的原理类似,利用了XML解析机制的漏洞,如果系统对用户输入<
,>
没有做转义的处理,攻击者可以修改XML的数据格式,或者添加新的XML节点,就会导致解析XML异常,导致XML注入攻击
如何注入?
如下XML是用于注册访问用户,其中用户名是由用户自己输入的
1 |
|
攻击者在输入用户的时候,可以构造 user1 < /user> < user role=“admin”>user2
数据去拼接XML,之后整个XML字符串将会变成如下格式。这样就添加了一个管理员权限的用户
1 |
|
如何防御?
使用安全的XML库
正确代码使用Dom4j来构建XML,Dom4j将会对文本数据进行XML编码,从而使得XML的原始结构和格式免受破坏,防止了XML注入
对用户输入的字段进行转码处理
使用实体编码对用户的输入进行转义
XPath注入
什么是XPath注入?
XPath注入攻击是指利用XPath 解析器的松散输入和容错特性,能够在 URL、表单或其它信息上附带恶意的XPath 查询代码,以获得权限信息的访问权并更改这些信息
XPath注入攻击是针对Web服务应用新的攻击方法,它允许攻击者在事先不知道XPath查询相关知识的情况下,通过XPath查询得到一个XML文档的完整内容
XPath注入发生在当站点使用用户输入的信息来构造请求以获取XML数据。攻击者对站点发送经过特殊构造的信息来探究站点使用的XML是如何构造的,从而进一步获取正常途径下无法获取的数据。当XML数据被用作账户验证时,攻击者还可以提升他的权限
如何注入?
XPath注入攻击主要是通过构建特殊的输入,这些输入往往是XPath语法中的一些组合,这些输入将作为参数传入Web 应用程序,通过执行XPath查询而执行入侵者想要的操作
注入对象不是数据库users表,而是一个存储数据的XML文件。因为xpath不存在访问控制,所以不会遇到许多在SQL注入中经常遇到的访问限制。 注入出现的位置也就是cookie
,headers
,request
parameters/input
等
如果一个网站某应用程序将数据保存在XML中,并且对用户的输入没有做限制,攻击者提交了没有经过处理的输入,就插入到 XPath 查询中,即产生Xpath注入,那么就攻击者就可能通过控制查询,获取数据,或者删除数据之类的操作
Xpath是xml路径语言,用于配置文件的查找。数据库就是xml文件。因此只要是利用XPath语法的Web 应用程序如果未对输入的XPath查询做严格的处理都会存在XPath注入漏洞。比如一些登录地址页面,搜索页面需要与xml交互的位置
Xpath直接注入
示例:
test.xml(存储用户名和密码)
1 |
|
php(用于接收传入参数,并进行XML查询)
1 |
|
使用simplexml_load_file()
函数返回类 SimpleXMLElement 的一个对象(该对象的属性包含 XML 文档中的数据)
攻击者在username
字段中构造恒真语句如' or 1=1 or ''='
进行闭合,获取所有user数据
Xpath盲注
如果遍历出整个XML文档,一般步骤如下:
1.盲注根节点
利用count(/*)
判断根下节点:
1 | ?name=' or count(/*) = 1 or '1' = '2 |
有返回结果证明存在一个根节点
利用substring分割根节点的每个字符,猜解第一级节点:
1 | ?name=' or substring(name(/*[position() = 1]),1,1)='r' or '1'='2 |
2.盲注root的下一级节点
判断root的下一级节点数:
1 | ?name=' or count(/root/*) = 1 or '1' = '2 |
有返回结果证明存在一个root的下一级节点
猜解root的下一级节点:
1 | ?name=' or substring(name(/root/*[position() = 1]),1,1)='u' or '1'='2 |
重复上述步骤,直至猜解出所有节点,最后来猜解节点中的数据或属性值
如何防御?
限制提交非法字符,对输入内容严格检查过滤,参数化XPath查询的变量
XML外部实体注入(XXE)
什么是XXE?
XXE漏洞全称XML External Entity Injection 即XML外部实体注入
XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件和代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站、发起Dos攻击等危害
如何注入?
与SQL相似,XXE漏洞也分为有回显和无回显
有回显,可以直接在页面中看到payload的执行结果或现象
无回显,又称为blind xxe,可以使用外带数据(OOB)通道提取数据。即可以引用远程服务器上的XML文件读取文件
读取任意文件
有回显
首先准备一个有XXE漏洞的文件,这里以php文件为例
示例代码:
1 |
|
payload:
1 |
|
读取文件,需URL编码后执行
通过构造外部实体payload,在 xml 中 &file ;
变成了外部文件1.txt
中内容,导致敏感信息泄露
无回显
无回显的文件读取可以通过 blind XXE 方法加上外带数据通道(ooB)来提取数据,先使用php://filter
协议获取目标文件的内容,然后将内容以http
请求发送到攻击服务器来读取数据。虽无法直接查看文件内容,但我们可以使用易受攻击的服务器作为代理,在外部网络上执行扫描以及代码。即,当无回显情况时,可以将数据发送到远程服务器(攻击服务器)
paylaod:
1 |
evil.dtd:
1 | %payload; |
进行XXE攻击后,服务器会把文件内容发送到攻击者服务器(这里是ubantu的apache日志记录)
ubantu查看apache日志记录命令:
1 | tail -f /var/log/apache2/access.log |
本地抓包也可以看到Base64编码后的文件内容
拒绝服务攻击(Dos)
常见的XML炸弹:当XML解析器尝试解析该文件时,由于DTD的定义指数级展开,这个1K不到的文件会占用到3G的内存
1 |
|
原理:递归引用,lol 实体具体还有 “lol” 字符串,然后一个 lol2 实体引用了 10 次 lol 实体,一个 lol3 实体引用了 10 次 lol2 实体,此时一个 lol3 实体就含有 10^2 个 “lol” 了,以此类推,lol9 实体含有 10^8 个 “lol” 字符串,最后再引用lol9
执行系统命令
在php环境下,xml命令执行需要php装有expect扩展,但该扩展默认没有安装,所以一般来说命令执行是比较难利用,但不排除
1 |
|
探测内网端口
1 |
|
如何防御?
使用开发语言提供的禁用外部实体的方法
php:
1 | libxml_disable_entity_loader(true); |
java:
1 | DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance(); |
Python:
1 | from lxml import etree |
过滤用户提交的XML数据
过滤关键字:<\!DOCTYPE
和<\!ENTITY
,或者SYSTEM
和PUBLIC
不允许XML中含有自己定义的DTD
参考:
从XML相关一步一步到XXE漏洞