浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

admin 2024年12月28日13:16:29评论8 views字数 7675阅读25分35秒阅读模式

0x00 前言

学习下最近爆出的Dubbo漏洞。

0x01 漏洞原理

Dubbo Provider即服务提供方默认使用dubbo协议来进行RPC通信,而dubbo协议默认是使用Hessian2序列化格式进行对象传输的,但是针对Hessian2序列化格式的对象传输可能会有黑白名单设置的限制,参考:https://github.com/apache/dubbo/pull/6378

针对这种场景,攻击者可以通过更改dubbo协议的第三个flag位字节来更改为使用Kryo或FST序列化格式来进行Dubbo Provider反序列化攻击从而绕过针对Hessian2反序列化相关的限制来达到RCE。

0x02 影响版本

  • Dubbo 2.7.0 to 2.7.8

  • Dubbo 2.6.0 to 2.6.9

  • Dubbo all 2.5.x versions (not supported by official team any longer)

0x03 环境搭建

https://github.com/apache/dubbo-spring-boot-project

下载2.7.3版本,添加Dubbo-Common依赖:

<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-common --><dependency>    <groupId>org.apache.dubbo</groupId>    <artifactId>dubbo-common</artifactId>    <version>2.7.3</version></dependency>

注意,dubbo-common必须<=2.7.3版本。

0x04 漏洞复现

恶意FST/Kryo序列化请求构造工具:https://github.com/Dor-Tumarkin/CVE-2021-25641-Proof-of-Concept

冲:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

0x05 调试分析

Kryo反序列化

在DecodeableRpcInvocation类的decode()函数中,通过serializationType为8、获取到反序列化器Kryo,然后调用readUTF()函数来读取dubbo协议对应的字段信息如dubbo协议版本、服务名称、服务版本、方法名、方法参数类型等:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

提取方法参数类型为类数组后,再循环对参数进行Kryo反序列化:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

从input中读取解析到type为HashMap,因此会调用Kryo的MapSerializer序列化器来读取input中的信息:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

其中会将解析到的key和value都通过调用map.put()来放入HashMap对象中,这里是有两对键值对放进去了:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

往下putVal()函数中会调用key即XString类的equals()函数来判断两个key值是否相等:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

这其中就会调用参数类的toString()函数,这里是com/alibaba/fastjson/JSON类的toString()函数,进而调用JSONSerializer的write()函数,从而触发Fastjson Gadget:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

最后,就是TemplatesImpl链的触发点了:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

此时函数调用栈:

getTransletInstance:455, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)write:-1, ASMSerializer_1_TemplatesImpl (com.alibaba.fastjson.serializer)write:270, MapSerializer (com.alibaba.fastjson.serializer)write:44, MapSerializer (com.alibaba.fastjson.serializer)write:280, JSONSerializer (com.alibaba.fastjson.serializer)toJSONString:863, JSON (com.alibaba.fastjson)toString:857, JSON (com.alibaba.fastjson)equals:392, XString (com.sun.org.apache.xpath.internal.objects)equals:104, HotSwappableTargetSource (org.springframework.aop.target)putVal:635, HashMap (java.util)put:612, HashMap (java.util)read:162, MapSerializer (com.esotericsoftware.kryo.serializers)read:39, MapSerializer (com.esotericsoftware.kryo.serializers)readClassAndObject:813, Kryo (com.esotericsoftware.kryo)readObject:136, KryoObjectInput (org.apache.dubbo.common.serialize.kryo)readObject:147, KryoObjectInput (org.apache.dubbo.common.serialize.kryo)decode:116, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)decode:73, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)decodeBody:132, DubboCodec (org.apache.dubbo.rpc.protocol.dubbo)decode:122, ExchangeCodec (org.apache.dubbo.remoting.exchange.codec)decode:82, ExchangeCodec (org.apache.dubbo.remoting.exchange.codec)decode:48, DubboCountCodec (org.apache.dubbo.rpc.protocol.dubbo)decode:90, NettyCodecAdapter$InternalDecoder (org.apache.dubbo.remoting.transport.netty4)decodeRemovalReentryProtection:502, ByteToMessageDecoder (io.netty.handler.codec)callDecode:441, ByteToMessageDecoder (io.netty.handler.codec)channelRead:278, ByteToMessageDecoder (io.netty.handler.codec)invokeChannelRead:374, AbstractChannelHandlerContext (io.netty.channel)invokeChannelRead:360, AbstractChannelHandlerContext (io.netty.channel)fireChannelRead:352, AbstractChannelHandlerContext (io.netty.channel)channelRead:1408, DefaultChannelPipeline$HeadContext (io.netty.channel)invokeChannelRead:374, AbstractChannelHandlerContext (io.netty.channel)invokeChannelRead:360, AbstractChannelHandlerContext (io.netty.channel)fireChannelRead:930, DefaultChannelPipeline (io.netty.channel)read:163, AbstractNioByteChannel$NioByteUnsafe (io.netty.channel.nio)processSelectedKey:682, NioEventLoop (io.netty.channel.nio)processSelectedKeysOptimized:617, NioEventLoop (io.netty.channel.nio)processSelectedKeys:534, NioEventLoop (io.netty.channel.nio)run:496, NioEventLoop (io.netty.channel.nio)run:906, SingleThreadEventExecutor$5 (io.netty.util.concurrent)run:74, ThreadExecutorMap$2 (io.netty.util.internal)run:30, FastThreadLocalRunnable (io.netty.util.concurrent)run:748, Thread (java.lang)

FTS反序列化

FTS反序列化也是类似的触发原理。

通过serializationType为9,获取到FST反序列化器进行反序列化操作:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

在FST反序列化过程中,也是将反序列化后的键值对put到HashMap对象中:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

往下是和Kryo一样的调用过程,即XString类的equals()函数中调用参数的toString触发Fastjson Gadget。

此时函数调用栈:

getTransletInstance:455, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)write:-1, ASMSerializer_1_TemplatesImpl (com.alibaba.fastjson.serializer)write:270, MapSerializer (com.alibaba.fastjson.serializer)write:44, MapSerializer (com.alibaba.fastjson.serializer)write:280, JSONSerializer (com.alibaba.fastjson.serializer)toJSONString:863, JSON (com.alibaba.fastjson)toString:857, JSON (com.alibaba.fastjson)equals:392, XString (com.sun.org.apache.xpath.internal.objects)equals:104, HotSwappableTargetSource (org.springframework.aop.target)putVal:635, HashMap (java.util)put:612, HashMap (java.util)instantiate:79, FSTMapSerializer (org.nustaq.serialization.serializers)instantiateAndReadWithSer:497, FSTObjectInput (org.nustaq.serialization)readObjectWithHeader:366, FSTObjectInput (org.nustaq.serialization)readObjectInternal:327, FSTObjectInput (org.nustaq.serialization)readObject:307, FSTObjectInput (org.nustaq.serialization)readObject:102, FstObjectInput (org.apache.dubbo.common.serialize.fst)decode:116, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)decode:73, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)decodeBody:132, DubboCodec (org.apache.dubbo.rpc.protocol.dubbo)decode:122, ExchangeCodec (org.apache.dubbo.remoting.exchange.codec)decode:82, ExchangeCodec (org.apache.dubbo.remoting.exchange.codec)decode:48, DubboCountCodec (org.apache.dubbo.rpc.protocol.dubbo)decode:90, NettyCodecAdapter$InternalDecoder (org.apache.dubbo.remoting.transport.netty4)decodeRemovalReentryProtection:502, ByteToMessageDecoder (io.netty.handler.codec)callDecode:441, ByteToMessageDecoder (io.netty.handler.codec)channelRead:278, ByteToMessageDecoder (io.netty.handler.codec)invokeChannelRead:374, AbstractChannelHandlerContext (io.netty.channel)invokeChannelRead:360, AbstractChannelHandlerContext (io.netty.channel)fireChannelRead:352, AbstractChannelHandlerContext (io.netty.channel)channelRead:1408, DefaultChannelPipeline$HeadContext (io.netty.channel)invokeChannelRead:374, AbstractChannelHandlerContext (io.netty.channel)invokeChannelRead:360, AbstractChannelHandlerContext (io.netty.channel)fireChannelRead:930, DefaultChannelPipeline (io.netty.channel)read:163, AbstractNioByteChannel$NioByteUnsafe (io.netty.channel.nio)processSelectedKey:682, NioEventLoop (io.netty.channel.nio)processSelectedKeysOptimized:617, NioEventLoop (io.netty.channel.nio)processSelectedKeys:534, NioEventLoop (io.netty.channel.nio)run:496, NioEventLoop (io.netty.channel.nio)run:906, SingleThreadEventExecutor$5 (io.netty.util.concurrent)run:74, ThreadExecutorMap$2 (io.netty.util.internal)run:30, FastThreadLocalRunnable (io.netty.util.concurrent)run:748, Thread (java.lang)

0x06 补丁分析

本地以2.7.9版本测试。

在高版本中已将com.esotericsoftware:kryo依赖去掉了,在使用Kryo序列化器进行反序列化获取KryoObjectInput对象时会报找不到KryoException类的错误:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

添加上对应的依赖:

<!-- https://mvnrepository.com/artifact/com.esotericsoftware/kryo --><dependency>    <groupId>com.esotericsoftware</groupId>    <artifactId>kryo</artifactId>    <version>4.0.2</version></dependency><!-- https://mvnrepository.com/artifact/de.javakaffee/kryo-serializers --><dependency>    <groupId>de.javakaffee</groupId>    <artifactId>kryo-serializers</artifactId>    <version>0.43</version></dependency>

其实就是CVE-2020-1948的补丁过滤拦截了:

浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

而且,自带的Fastjson版本为1.2.70,AutoType会自动拦截掉TemplatesImpl类。

0x07 参考

https://www.checkmarx.com/blog/technical-blog/the-0xdabb-of-doom-cve-2021-25641/

原文始发于微信公众号(98KSec):浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年12月28日13:16:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   浅析Dubbo Kryo/FST反序列化漏洞(CVE-2021-25641)https://cn-sec.com/archives/794733.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息