前言
学习下Apache Dubbo系列的经典漏洞
CVE-2019-17564
影响版本
- Dubbo 2.7.0 to 2.7.4
- Dubbo 2.6.0 to 2.6.7
- Dubbo all 2.5.x versions
环境准备
从https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-http下载源代码,在pom中切换dubbo版本,发现无法找到存在该漏洞的版本,手动下载jar包添加,并添加可利用依赖common-collections3.2
漏洞分析
在dubbo开启http协议后通过http协议的请求都会经过org.apache.dubbo.rpc.protocol.http.HttpProtocol.InternalHandler#handle方法,所以在此处打断点
利用ysoserial生成payload
1 | java -jar ysoserial.jar CommonsCollections6 "/System/Applications/Calculator.app/Contents/MacOS/Calculator">cc6 |
然后发送
1 | curl http://127.0.0.1:8081/org.apache.dubbo.samples.http.api.DemoService --data-binary @cc6 |
会发现断在我们的断点处,向下跟踪
170行会根据我们传入的路径寻找处理器,我们看看this.skeletonMap的值
key对应着请求路径,value是一个HttpInvokerServiceExporter类的实例;接着在177行使用获取到的处理器处理请求,调用的是org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter#handleRequest
接着会将请求发送到org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter#readRemoteInvocation(javax.servlet.http.HttpServletRequest)方法中
该方法中将请求对象和我们发送的序列化内容传入org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter#readRemoteInvocation(javax.servlet.http.HttpServletRequest, java.io.InputStream)方法中
在该方法中首先会对我们传入的序列化内容转换成ObjectInputStream类型,然后传入org.springframework.remoting.rmi.RemoteInvocationSerializingExporter#doReadRemoteInvocation方法中
在该方法中直接对传入的ObjectInputStream对象进行反序列化操作,导致漏洞利用链的触发
漏洞修复
将dubbo切换到高版本进行调试,发现在org.apache.dubbo.rpc.protocol.http.HttpProtocol.InternalHandler#handle中将请求处理器HttpInvokerServiceExporter换为了JsonRpcServer,在后续的处理中,没有进行反序列化操作
CVE-2020-1948
影响版本
- Dubbo 2.7.0 to 2.7.6
- Dubbo 2.6.0 to 2.6.7
- Dubbo all 2.5.x versions
漏洞分析
可以参考https://www.cnblogs.com/zhengjim/p/13204194.html 中的环境搭建部分进行测试
参考网上的利用脚本
1 | from dubbo.codec.hessian2 import Decoder,new_object |
由于最后是利用rome组件的链条完成利用,所以直接在rome调用链中的com.rometools.rome.feed.impl.ToStringBean#toString()处下断点,发送poc,断点断下后向上查看调用栈,可以看到是由org.apache.dubbo.rpc.RpcInvocation#toString方法进入到ToStringBean的,其中的arguments包含着ToStringBean的实例
接着向上寻找会发现org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#getInvoker方法中的代码引发了后面的利用过程,关键点在一处异常处理中
1 | //关键代码 |
其中inv是一个DecodeableRpcInvocation 类的实例,里面存储着上文提到的arguments
在处理异常的过程中,会隐式调用toString方法,进而触发后面的利用链;那么我们来分析下何时会抛出异常
当exporter是null的时候,会进行异常处理,也就是在this.exporterMap中找不到键值为servicekey的值,其中servicekey是用户请求的servicename,this.exporterMap是provider定义的service,也就是说当用户请求的service在provider中找不到时,会触发该漏洞
2.7.7补丁分析及绕过
将dubbo版本切换到2.7.7,然后发送payload
提示Service not found:,搜索下异常
可以看到在抛出异常之前有一个判断,跟进去if中的两个方法
当请求的方法名是$invoke , $invokeAsync ,$echo其中之一时,不会抛出异常,那么我们可以修改payload如下
1 | from dubbo.codec.hessian2 import Decoder,new_object |
用https://github.com/HyCXSS/JNDIScan 项目检测下jndi注入请求
可以看道成功收到了provider的ldap请求
2.7.8补丁修复
将版本切换到2.7.8,可以看到对调用方法的参数类型做了校验,
我们传入的参数类型是Lcom/rometools/rome/feed/impl/ToStringBean; ,自然是不符合的,也就会抛出异常
CVE-2021-43297
影响版本
- Apache Dubbo 2.6.x versions prior to 2.6.12
- Apache Dubbo 2.7.x versions prior to 2.7.15
- Apache Dubbo 3.0.x versions prior to 3.0.5
漏洞分析
首先看一下版本diff
https://github.com/apache/dubbo-hessian-lite/commit/a35a4e59ebc76721d936df3c01e1943e871729bd#
都是隐式触发toString的点被修复了,其中值得关注的是com.alibaba.com.caucho.hessian.io.Hessian2Input#expect 在反序列化过程中多处存在,那么我们可以分析下如何触发异常来让我们到达toString触发点,首先分析下反序列化的过程
首先会使用com.alibaba.com.caucho.hessian.io.Hessian2Input#readObjectDefinition来恢复类的类型和字段名
然后进入com.alibaba.com.caucho.hessian.io.Hessian2Input#readObject(java.util.List<java.lang.Class<?>>)来恢复类的实例
跟进去
接着跟进
获取到反序列化器为JavaDeserializer,然后进行反序列化,接着跟进com.alibaba.com.caucho.hessian.io.JavaDeserializer#readObject(com.alibaba.com.caucho.hessian.io.AbstractHessianInput, java.lang.String[])
首先恢复类的实例,然后接着调用com.alibaba.com.caucho.hessian.io.JavaDeserializer#readObject(com.alibaba.com.caucho.hessian.io.AbstractHessianInput, java.lang.Object, java.lang.String[])来恢复属性的值
首先遍历属性,获取属性对应的反序列化器进行反序列化
当字段的类型是object时,会再次调用com.alibaba.com.caucho.hessian.io.Hessian2Input#readObjectDefinition来获取对象的信息
首先会进行readstring操作,其中这个readString方法中就存在着对expect的调用
如果在该处readString时使其异常进入expect,我们就可以触发后面的toString链,这里我们可以将属性的值更改掉,如图
正常在readString中首先会执行read操作,读到F,我们可以控制换掉这个F,也就是更改tag的值
在这里我们选择0x43,也就是67,然后进入expect
在这里会readobject,也就是会读0x43 后面的值,然后触发toString,我们在0x43后拼接我们构造的恶意对象即可
参考链接
https://gv7.me/articles/2020/cve-2019-17564-dubbo-http-deserialization-vulnerability/
https://l3yx.github.io/2020/08/25/Apache-Dubbo-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0%E7%AC%94%E8%AE%B0/
https://www.cnblogs.com/zhengjim/p/13204194.html
http://rui0.cn/archives/1338