温馨提示: 本文仅供网络安全技术交流,请勿用于非法用途。所有操作需获得授权,否则后果自负,与本文作者及平台无关。请务必遵守法律法规!
各位老铁,今天咱们来聊聊一个让无数Java程序员夜不能寐的话题——反序列化漏洞。这玩意儿就像潜伏在代码里的幽灵,一不小心就可能给你带来灭顶之灾。不过别慌,看完这篇文章,保证你也能玩转反序列化,成为安全界的弄潮儿!
开胃小菜:啥是反序列化?
简单来说,序列化就是把Java对象变成一串字节,方便存储和传输;反序列化就是把这串字节还原成Java对象。 就像把变形金刚折叠成一个盒子,需要的时候再展开变回去。
序列化/反序列化:程序员的左右手
- 序列化 (Serialization): 把Java对象转化为可传输的字节序列,就像把你的想法压缩成一个文件,方便发送给别人。
- 反序列化 (Deserialization): 把字节序列还原为Java对象,相当于别人收到了你的文件,解压缩后理解了你的想法。
为啥要搞序列化?
想象一下,你的程序运行了一段时间,产生了一些重要的数据,比如用户登录信息、购物车内容等等。这些数据都存在内存里,一旦程序关闭或者服务器重启,数据就全没了!这可咋整?
这时候,序列化就派上用场了。它可以把内存中的数据保存到硬盘上,或者通过网络传输到其他地方。这样,即使程序重启,数据也不会丢失,是不是很神奇?
序列化的三大妙用:
-
持久化内存数据:让数据“永生”
- 场景: 比如网站保持登录状态。
-
原理: 客户端用Cookie记住你的身份,服务端用Session保存你的登录信息。如果Session数据只存在内存里,服务器一重启就GG了。所以,需要把Session数据序列化到硬盘上,让你的登录状态“永生”。
2. 网络传输对象:跨系统的数据交流 -
场景: 两个不同的系统需要交换Java对象。
-
原理: 把Java对象序列化成二进制字节流,通过网络发送给对方。对方收到后,再反序列化成Java对象,就可以直接使用了。
3. 远程方法调用(RMI):像调用本地方法一样简单 -
这个比较高级,涉及到分布式系统,以后有机会再详细介绍。
序列化后的数据是啥样的?字符串还是二进制?
这个问题问得好!其实,两者都可以!
在PHP里,序列化后的数据通常是人类可读的字符串。那么,Java可以吗?
当然可以!
早些年,Java程序员喜欢用JSON格式来传输数据。
数据格式进化史:
- 定长报文格式: 浪费空间,直接Pass。
- 变长报文格式: 比定长好点,但还是不够灵活。
-
XML格式: 曾经的王者,各种标签看着就头大。
- 优点: 可以用DTD进行格式校验,提前发现错误。
- 缺点: 太笨重,代码冗余。
- JSON格式: 现在的当红炸子鸡,轻巧灵活,人见人爱。
Java序列化实战:
1. JSON序列化 (Fastjson):
* **步骤:**
1. 引入Fastjson库(在`pom.xml`中添加依赖)。
2. 定义一个`Person`类,包含`name`和`age`属性。
public class Person {
private String name;
private int age;
// 省略构造方法、getter和setter
}
3. 创建`Person`对象,并用`Fastjson.toJSONString()`方法进行序列化。
4. 反序列化:用`Fastjson.parseObject()`方法将JSON字符串转换回`Person`对象。
Person person = new Person("fast", 999);
String jsonString = JSON.toJSONString(person);
Person parsedPerson = JSON.parseObject(jsonString, Person.class);
System.out.println(parsedPerson.getName()); // 输出: fast
* **代码示例:**
// 引入Fastjson库
import com.alibaba.fastjson.JSON;
public class Main {
public static void main(String[] args) {
// 创建Person对象
Person person = new Person();
person.setName("fast");
person.setAge(999);
// 序列化
String jsonString = JSON.toJSONString(person);
System.out.println("序列化结果:" + jsonString);
// 反序列化
Person parsedPerson = JSON.parseObject(jsonString, Person.class);
System.out.println("反序列化结果:" + parsedPerson.getName() + ", " + parsedPerson.getAge());
}
}
* **效果展示:**

2. JDK自带的序列化:
* **步骤:**
1. 让`Person`类实现`Serializable`接口(这是一个标记接口,告诉JVM这个类可以被序列化)。
2. 使用`ObjectOutputStream`和`ObjectInputStream`进行序列化和反序列化。
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 创建Person对象
Person person = new Person();
person.setName("wuya");
person.setAge(666);
// 序列化
FileOutputStream fileOutputStream = new FileOutputStream("person.bin");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(person);
objectOutputStream.close();
fileOutputStream.close();
// 反序列化
FileInputStream fileInputStream = new FileInputStream("person.bin");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Person parsedPerson = (Person) objectInputStream.readObject();
objectInputStream.close();
fileInputStream.close();
System.out.println("反序列化结果:" + parsedPerson.getName() + ", " + parsedPerson.getAge());
}
}
* **代码示例:**
import java.io.*;
public class Person implements Serializable {
private String name;
private int age;
// 省略构造方法、getter和setter
}
* **效果展示:**

打开序列化后的二进制文件,你会看到一些神秘的代码,比如`AC ED ...`。这些代码代表着Java序列化的规范,感兴趣的同学可以去Java官网查阅。

重头戏:JDK反序列化漏洞
前面说了这么多,终于要进入正题了!
漏洞成因:
用JDK进行反序列化时,需要实现Serializable
接口,并且会调用readObject()
方法。
关键就在这里:readObject()
方法是可以自定义的!
如果你自定义了一个readObject()
方法,并且在里面执行了一些恶意代码(比如打开计算器),那么在反序列化时,就会执行你自定义的恶意代码,从而导致漏洞。
代码示例:
import java.io.*;
public class Person implements Serializable {
private String name;
private int age;
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
// 执行恶意代码
Runtime.getRuntime().exec("calc");
in.defaultReadObject();
}
// 省略构造方法、getter和setter
}
执行效果:
漏洞利用:
如果有一个接口允许你上传序列化后的二进制文件(或者JSON格式的字符串),那么你就可以构造一个包含恶意readObject()
方法的类,上传到服务器,让服务器进行反序列化,从而执行你的恶意代码。
等等!事情并没有这么简单!
你构造的类不一定存在于目标服务器的项目中。你需要找到目标项目中已经存在的,并且满足以下两个条件的类:
- 可以重写
readObject()
方法。 readObject()
方法中的参数可以被你控制,也就是说,你可以让它执行你想要的命令。
幸运的是,还真有这样的类! 比如AnnotationInvocationHandler
类和BadAttributeValueExpException
类。
经典案例:Apache Commons Collections反序列化漏洞
这个漏洞曾经轰动一时,利用了Apache Commons Collections库中的一些类,构造了一个精妙的利用链,可以在目标服务器上执行任意代码。
由于篇幅限制,这里就不展开讲解了,感兴趣的同学可以自行搜索学习。
总结:
Java反序列化漏洞是一个非常危险的漏洞,攻击者可以利用它在目标服务器上执行任意代码。
防御方法:
- 不要轻易相信任何外部数据,对所有反序列化的数据进行严格的校验。
- 尽量避免使用JDK自带的序列化机制,可以考虑使用JSON等更安全的序列化方式。
- 及时更新第三方库,修复已知的反序列化漏洞。
希望这篇文章能让你对Java反序列化漏洞有一个更深入的了解。记住,安全无小事,时刻保持警惕,才能保护你的系统免受攻击!
黑客/网络安全学习包
资料目录
-
成长路线图&学习规划
-
配套视频教程
-
SRC&黑客文籍
-
护网行动资料
-
黑客必读书单
-
面试题合集
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
*************************************优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享*************************************
1.成长路线图&学习规划
要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费。
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
*************************************优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享*************************************
2.视频教程
很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
*************************************优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享*************************************
3.SRC&黑客文籍
大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录
SRC技术文籍:
黑客资料由于是敏感资源,这里不能直接展示哦!
4.护网行动资料
其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!
5.黑客必读书单
**
**
6.面试题合集
当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。
更多内容为防止和谐,可以扫描获取~
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
*************************************优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享*********************************