反序列化初解
字数 923 2025-08-10 19:49:08
反序列化漏洞原理与实例详解
1. PHP反序列化漏洞
漏洞成因
PHP中的反序列化漏洞通常出现在魔术方法被不当使用时。在提供的示例中,__sleep()魔术方法被用来执行危险操作:
class VulnerableClass {
public function __sleep() {
if (isset($_GET['cmd']) && $_GET['cmd'] == 'xiu') {
system('calc'); // 执行Windows计算器
}
return [];
}
}
关键点:
__sleep()方法在对象被序列化时自动调用- 直接执行用户可控参数传入的系统命令
- 导致任意命令执行风险
2. Java类继承与重写
类继承示例
public class Person {
public int age;
public String name;
public void talk() {
System.out.println("Person 说话了");
}
}
public class Student extends Person {
public int score;
@Override
public void talk() {
System.out.println("Student 说话了");
}
}
关键点:
Student类继承Person类的属性和方法- 使用
@Override注解显式表示方法重写 - 子类可以扩展父类的功能
方法重写测试
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.talk(); // 输出"Student 说话了"
Person p1 = new Person();
p1.talk(); // 输出"Person 说话了"
}
}
关键点:
- 子类重写的方法会覆盖父类方法
- 实现了多态性
- 运行时根据实际对象类型调用相应方法
3. Java序列化与反序列化基础
基本序列化实现
import java.io.*;
public class Person implements Serializable {
public int age;
public String name;
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
// 默认反序列化操作
in.defaultReadObject();
}
}
public class Test {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.age = 18;
p.name = "xiu";
serialize(p, "xiu.bin");
System.out.println("反序列化结果:" + deserialize("xiu.bin"));
}
public static void serialize(Object obj, String filePath) throws IOException {
try (FileOutputStream fileOut = new FileOutputStream(filePath);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut)) {
objectOut.writeObject(obj);
}
}
public static Object deserialize(String filePath)
throws IOException, ClassNotFoundException {
try (FileInputStream fileIn = new FileInputStream(filePath);
ObjectInputStream objectIn = new ObjectInputStream(fileIn)) {
return objectIn.readObject();
}
}
}
关键点:
- 实现
Serializable接口使类可序列化 readObject方法在反序列化时自动调用- 序列化使用
ObjectOutputStream - 反序列化使用
ObjectInputStream
4. Java反序列化漏洞原理
危险的反序列化实现
import java.io.*;
public class Person implements Serializable {
public int age;
public String name;
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
Runtime.getRuntime().exec("calc"); // 执行计算器
in.defaultReadObject(); // 默认反序列化操作
}
}
public class Test {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.age = 18;
p.name = "xiu";
serialize(p, "xiu.bin");
System.out.println("反序列化结果:" + deserialize("xiu.bin"));
}
// serialize和deserialize方法同上
}
关键点:
- 重写
readObject方法时插入恶意代码 - 反序列化时会自动执行
readObject中的代码 - 导致任意命令执行漏洞
- 攻击者可以构造恶意序列化数据触发漏洞
5. 反序列化漏洞攻击示例
漏洞类定义
import java.io.Serializable;
public class ExploitMe implements Serializable {
private String data;
public ExploitMe(String data) {
this.data = data;
}
public String getData() {
return data;
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
System.out.println("Executing command: " + data);
Runtime.getRuntime().exec(data); // 执行data中的命令
}
}
攻击者构造恶意序列化数据
import java.io.*;
import java.nio.file.*;
public class Exploit {
public static void main(String[] args) throws Exception {
// 创建包含恶意命令的对象
ExploitMe maliciousObject = new ExploitMe("calc.exe");
// 序列化恶意对象
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(maliciousObject);
objectOutputStream.close();
byte[] serializedData = byteArrayOutputStream.toByteArray();
// 存储到文件中
Files.write(Paths.get("malicious_data.bin"), serializedData);
// 模拟目标系统反序列化
byte[] receivedData = Files.readAllBytes(Paths.get("malicious_data.bin"));
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(receivedData);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
ExploitMe deserializedObject = (ExploitMe) objectInputStream.readObject();
}
}
关键攻击流程:
- 攻击者创建包含恶意命令的
ExploitMe对象 - 序列化该对象为字节序列
- 将序列化数据发送到目标系统(如通过文件、网络等)
- 目标系统反序列化数据时自动执行恶意命令
6. 防御措施
- 输入验证:不要反序列化不受信任的数据
- 白名单验证:使用
ObjectInputFilter限制可反序列化的类 - 避免危险方法:不要在
readObject中执行危险操作 - 使用替代方案:考虑使用JSON等更安全的序列化格式
- 更新依赖:及时修复已知漏洞的第三方库
总结
反序列化漏洞是一种严重的安全威胁,攻击者可以通过构造恶意序列化数据在目标系统上执行任意代码。理解其原理对于开发安全应用至关重要。开发者应当遵循安全编码实践,避免直接反序列化不受信任的数据,并对序列化操作实施严格的安全控制。