Apache Druid RCE分析(CVE-2021-25646)

admin 2022年6月2日07:51:21评论150 views字数 7844阅读26分8秒阅读模式


炒个冷饭,毕竟看了,留个笔记

PS:我尽力了.....只能写成这样了2333333333333333333333


一、调试环境



https://archive.apache.org/dist/druid/0.20.1/

这里尝试了几种常规的调试方法都不行,然后看到conf目录下存在jvm.config,一搜好多,因为我们的启动脚本为start-micro-quickstart,所以最后范围锁定在这几个

Apache Druid RCE分析(CVE-2021-25646)

一开始踩了一个坑,D:javadruiddruid runapache-druid-0.20.0confdruidsingle-servermicro-quickstartrouterruntime.properties 中我看到了8888端口,这恰恰也是我们的web服务端口,下意识就改了这个jvm.config

Apache Druid RCE分析(CVE-2021-25646)

某些断点可以停住,但是我们漏洞出发点并不行,后来经过Smi1e师傅的提示,需要我改错了

Apache Druid RCE分析(CVE-2021-25646)

在此感谢~

 

二、漏洞分析



网上分析文章就只有阿里发出的,拿出上学的时候做阅读理解的本事,使劲看吧....

1.定位JavaScriptDimFIlter

阿里爸爸文章一开始就提出了利用的关键类JavaScriptDimFilter,反思一下,因为对Java相关的JavaScript知识储备几乎是0,看到fasterxml就一心想着反序列化了.........

这里简单提一下Javascript,Druid支持在运行时动态注入JavaScript,且不会在沙箱中执行Java脚本,因此它们具有对计算机的完全访问权限。因此,JavaScript函数允许用户在druid进程内执行任意代码。因此,默认情况下,JavaScript是禁用的。但是,在开发/登台环境或受保护的生产环境中,可以通过设置configuration属性 来启用它们druid.javascript.enabled = true。

这里提到了关于漏洞的关键点:druid.javascript.enabled,留个坑,稍后提到。

 

2.关于JsonCreator注解、JsonProperty注解、以及CreatorProperty类型

文章中提到了两个注解,以及一个类(参数类型),这里需要去补一下Jackson的一些知识了

@JasonCreator

该注解用在对象的反序列时指定特定的构造函数或者工厂方法。在反序列化时,Jackson默认会调用对象的无参构造函数,如果我们不定义任何构造函数,Jvm会负责生成默认的无参构造函数。但是如果我们定义了构造函数,并且没有提供无参构造函数时,Jackson会报错

再回到@JsonCreator注解,其作用就是,指定对象反序列化时的构造函数或者工厂方法,如果默认构造函数无法满足需求,或者说我们需要在构造对象时做一些特殊逻辑,可以使用该注解。该注解需要搭配@JsonProperty使用

@JsonProperty

此注解作用于属性上,作用是把该属性的名称序列化成另一个自己想要的名称

对属性名进行重命名,在java里我们墨守规定驼峰命名,但是在一些特殊的场合下,比如数据库是下划线等,再此我们就可以进行映射

对属性名称重命名,比如在很多场景下Java对象的属性是按照规范的驼峰书写,但在数据库设计时使用的是下划线连接方式,此处在进行映射的时候 

有了对注解的理解,再来看这句话,以及JavaScriptDimFilter的构造函数

Apache Druid RCE分析(CVE-2021-25646)

Apache Druid RCE分析(CVE-2021-25646)

JavaScriptDimFilter的构造函数是用JasonCreator修饰的,也就说JavaScriptDimFilter这个类在反序列化(这里指的是从Json数据转化为对象)时,Jackson会调用这个构造方法,且由于dimesion、function、extractionFn、filterTuning都有@JasonProperty注解修饰,Jackson在在反序列化处理解析到JavaScriptDimFilter时,都会被封装为CreatorProterty类型,而对于没有被标记@JasonProperty的config参数,会创建一个name为””的CreatorProperty

Apache Druid RCE分析(CVE-2021-25646)

跟到这里提出了一个疑问,Jackson是怎样将org.apache.druid.js.JavaScriptConfig注入到里面的?留坑,稍后回答。

Apache Druid RCE分析(CVE-2021-25646)

3.Jackson解析用户输入

(1) Jersey的初始配置注入部分

1.HTTP Server端采用的是Jersey框架,所有的配置信息都由Guice框架在启动的时候进行绑定注入,比如利用的JavaScriptConfig,初始化的时候读取配置文件中的druid.javascript.enabled绑定到JavaScriptConfig的enabled field,这部分是非本地用户不可控的。

对应了上文提到的druid.javascript.enabled,我尝试在druid中的配置文件找这个开关的配置,反编译后全局搜javascript关键字都没找到,后来请教了下Litch1师傅,说这个是默认配置,没有具体去跟,具体可以看下有个test测试里有这部分:

Apache Druid RCE分析(CVE-2021-25646)

 

(2) Jackson获取对应的creatorProperty(JavaScriptConfig)

文中直接定位到了com.fasterxml.jackson.databind.deser.BeanDeserializer#_deserializeUsingPropertyBased方法

会拿解析到的json串中的“键名”去查找当前解析对象中对应的creatorProperty,这步对应的是findCreatorProperty方法,findCreatorProperty方法会去_propertyLookup 这个HashMap中查找”键名”对应的属性,在_propertyLookup中可以看到其中没有用JsonProperty注释修饰的JavaScriptConfig的键为””,要是json串中的键也为””,就能匹配上,取出JavaScriptConfig对应的creatorProperty

跟着文章将视线集中到com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator#findCreatorProperty(java.lang.String)

Apache Druid RCE分析(CVE-2021-25646)

可以看到它在一个for循环中,for循环遍历了p(JsonParser,这里稍微不准确的理解为存储了待处理的Json数据),按照Json层级结构一层一层的处理Json数据,因为payload较长,快进到“”处理逻辑,从P中取到propName,然后进入findCreatorProperty

Apache Druid RCE分析(CVE-2021-25646)

this._propertyLookup是个数组,直接取到我们想要的JavaScriptConfig对应的creatorProperty

Apache Druid RCE分析(CVE-2021-25646)

还是之前留的坑,这个Hashmap是怎么初始化的?Jackson是怎样将org.apache.druid.js.JavaScriptConfig注入到里面的?这里仔细跟一下

Apache Druid RCE分析(CVE-2021-25646)

这个this,也就是creator

Apache Druid RCE分析(CVE-2021-25646)

Apache Druid RCE分析(CVE-2021-25646)

这里仔细跟下调用栈跳到上一步

deserializeFromObjectUsingNonDefault:1287, BeanDeserializerBase,Hashmap被存在了((BeanDeserializer)this)._propertyBasedCreator中

Apache Druid RCE分析(CVE-2021-25646)

再往上,deserializeFromObject:326, BeanDeserializer 还是this._propertyBasedCreator,也就是BeanDeserializer的属性

Apache Druid RCE分析(CVE-2021-25646)

一直向上跟进,看到了BeanDeserializer调用deserialize方法

可以看到这里的deser中已经初始化完毕了_propertyLookup Hashmap

Apache Druid RCE分析(CVE-2021-25646)

再去看deser的初始化情况

Apache Druid RCE分析(CVE-2021-25646)

其实跟到这里就想停了,因为payload里我们给的type是javascript,反序列化时会Jackson会解析到相应的实体类也就是JavaScriptDimFilter

Apache Druid RCE分析(CVE-2021-25646)

继续走跟到com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase#_findDeserializer中

Apache Druid RCE分析(CVE-2021-25646)

经过一层层的变量传递,来到了deserializeTypedFromObject:97, AsPropertyTypeDeserializer

Apache Druid RCE分析(CVE-2021-25646)

deserialize:527, SettableBeanProperty 这时这个hashmap 被赋值到了SettableBeanProperty的_valueTypeDeserializer参数上

Apache Druid RCE分析(CVE-2021-25646)

然后向前追踪SettableBeanProperty,最终又回到了BeanDeserializer

Apache Druid RCE分析(CVE-2021-25646)

可以看到creatorProp通过findCreatorProperty中获得

Apache Druid RCE分析(CVE-2021-25646)

又回来了.....这时候就懵逼了一会儿,不过感谢idea

Apache Druid RCE分析(CVE-2021-25646)

_deserializeUsingPropertyBased:417, BeanDeserializer  被调用了四次,回头看下我们的payload Json数据是四层,嗯,对上了....大概是這個樣子的吧.....这里有点懵

这里放一下部分调用栈吧,

_findDeserializer:198, TypeDeserializerBase (com.fasterxml.jackson.databind.jsontype.impl)_deserializeTypedForId:113, AsPropertyTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)deserializeTypedFromObject:97, AsPropertyTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)deserializeWithType:254, AbstractDeserializer (com.fasterxml.jackson.databind.deser)deserialize:527, SettableBeanProperty (com.fasterxml.jackson.databind.deser)_deserializeWithErrorWrapping:528, BeanDeserializer (com.fasterxml.jackson.databind.deser)_deserializeUsingPropertyBased:417, BeanDeserializer (com.fasterxml.jackson.databind.deser) [4]deserializeFromObjectUsingNonDefault:1287, BeanDeserializerBase (com.fasterxml.jackson.databind.deser)deserializeFromObject:326, BeanDeserializer (com.fasterxml.jackson.databind.deser)deserialize:159, BeanDeserializer (com.fasterxml.jackson.databind.deser)deserialize:530, SettableBeanProperty (com.fasterxml.jackson.databind.deser)_deserializeWithErrorWrapping:528, BeanDeserializer (com.fasterxml.jackson.databind.deser)_deserializeUsingPropertyBased:417, BeanDeserializer (com.fasterxml.jackson.databind.deser) [3]deserializeFromObjectUsingNonDefault:1287, BeanDeserializerBase (com.fasterxml.jackson.databind.deser)deserializeFromObject:326, BeanDeserializer (com.fasterxml.jackson.databind.deser)deserialize:159, BeanDeserializer (com.fasterxml.jackson.databind.deser)deserialize:530, SettableBeanProperty (com.fasterxml.jackson.databind.deser)_deserializeWithErrorWrapping:528, BeanDeserializer (com.fasterxml.jackson.databind.deser)_deserializeUsingPropertyBased:417, BeanDeserializer (com.fasterxml.jackson.databind.deser) [2]deserializeFromObjectUsingNonDefault:1287, BeanDeserializerBase (com.fasterxml.jackson.databind.deser)deserializeFromObject:326, BeanDeserializer (com.fasterxml.jackson.databind.deser)deserialize:159, BeanDeserializer (com.fasterxml.jackson.databind.deser)deserialize:530, SettableBeanProperty (com.fasterxml.jackson.databind.deser)_deserializeWithErrorWrapping:528, BeanDeserializer (com.fasterxml.jackson.databind.deser)_deserializeUsingPropertyBased:417, BeanDeserializer (com.fasterxml.jackson.databind.deser) [1]deserializeFromObjectUsingNonDefault:1287, BeanDeserializerBase (com.fasterxml.jackson.databind.deser)deserializeFromObject:326, BeanDeserializer (com.fasterxml.jackson.databind.deser)_deserializeOther:194, BeanDeserializer (com.fasterxml.jackson.databind.deser)deserialize:161, BeanDeserializer (com.fasterxml.jackson.databind.deser)_deserializeTypedForId:130, AsPropertyTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)deserializeTypedFromObject:97, AsPropertyTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)deserializeWithType:254, AbstractDeserializer (com.fasterxml.jackson.databind.deser)deserialize:68, TypeWrappedDeserializer (com.fasterxml.jackson.databind.deser.impl)_bind:1682, ObjectReader (com.fasterxml.jackson.databind)readValue:977, ObjectReader (com.fasterxml.jackson.databind)readFrom:814, ProviderBase (com.fasterxml.jackson.jaxrs.base)getEntity:490, ContainerRequest (com.sun.jersey.spi.container)getValue:123, EntityParamDispatchProvider$EntityInjectable (com.sun.jersey.server.impl.model.method.dispatch)getInjectableValues:86, InjectableValuesProvider

(4) 反序列化相应参数

拿到对应的creatorProperty之后就会将用户输入的json串中这个键对应的根据类型去反序列相应的参数,

Apache Druid RCE分析(CVE-2021-25646)

(5) 触发漏洞

最后漏洞的利用点就是利用config为true之后绕过了对于config的检查

Apache Druid RCE分析(CVE-2021-25646)

然后进行JavaScript的执行。


三、总结一下



这个漏洞主要就是根据Jackson解析特性(解析name为""时)会将value值绑定到对象(JavaScriptDimFilter,type为javascript时指定的)的对应参数(config)上,造成JavaScriptDimFilter中function属性中的javascript代码被执行。


四、补丁分析



最新版本payload会报错

Apache Druid RCE分析(CVE-2021-25646)

官方修复

Apache Druid RCE分析(CVE-2021-25646)

看下调试过程 this._propertyLookup hashmap中只剩下了四个

Apache Druid RCE分析(CVE-2021-25646)

直接干掉了""对应的解析,这就阻断了JavaScriptConfig对应的creatorProperty生成,hashmap中将不存在JavaScriptConfig,后面的链也就断了.....无法打开JavaScript执行开关。

其实问了下洞主,说实际上还应该跟下具体Jackson执行逻辑具体是怎么修复的,但是那个递归搞得我太头疼了,暂时先这样吧....


五、参考链接



https://mp.weixin.qq.com/s/McAoLfyf_tgFIfGTAoRCiw 文中引用大多来自于此

https://druid.apache.org/docs/0.19.0/tutorials/index.html

https://blog.csdn.net/u010900754/article/details/105859959

 

PS:感谢Litch1 和 Smi1e 指点....wtcl  Apache Druid RCE分析(CVE-2021-25646)Apache Druid RCE分析(CVE-2021-25646)Apache Druid RCE分析(CVE-2021-25646)



原文始发于微信公众号(赛博少女):Apache Druid RCE分析(CVE-2021-25646)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年6月2日07:51:21
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Apache Druid RCE分析(CVE-2021-25646)http://cn-sec.com/archives/880025.html

发表评论

匿名网友 填写信息