烟消火灭网

2015年,WebLogic 反序列化漏洞CVE-2015-4852)被公开时,很多Java开发者第一次意识到:一个看似普通的ObjectInputStream.readObject()调用,能把整个

JAVA反序列化漏洞

2015年,反序WebLogic 反序列化漏洞(CVE-2015-4852)被公开时,列化漏洞很多Java开发者第一次意识到:一个看似普通的反序ObjectInputStream.readObject()调用,能把整个服务器变成攻击者的列化漏洞提权跳板。这不是反序理论推演,是列化漏洞真实发生在生产环境里的远程代码执行。Apache Commons Collections 这个基础库,反序被硬生生改造成了攻击链的列化漏洞弹药。

问题出在Java反序列化的反序设计哲学上。序列化机制允许把对象状态转成字节流存储或传输,列化漏洞反序列化则是反序逆过程。关键在于,列化漏洞readObject()在还原对象时,反序会调用对象自身的列化漏洞readObject方法,而攻击者可以构造一条链——从入口类开始,反序经过一系列readObject、invoke、transform调用,最终触发Runtime.exec()。这条链上的每个类都来自合法库,没有任何一个环节是“漏洞类”,但组合起来就是完整的RCE。

Commons Collections 的 InvokerTransformer 是经典利用点。它实现了 Transformer 接口,transform()方法通过反射调用任意方法。攻击者把 Runtime.class 和 exec 方法名塞进去,再套上 ChainedTransformer,最后用 AnnotationInvocationHandler 的 readObject 触发整条链。这段代码在GitHub上流传极广,我见过不少渗透测试报告直接粘贴使用。

Java 官方后来加了序列化过滤机制,JEP 290 在 JDK 9 引入,JDK 8u121 开始支持。但现实很骨感——大量中间件和框架自己实现了序列化协议,WebLogic、JBoss、Jenkins 都中过招。更麻烦的是,过滤机制需要显式配置白名单,很多老系统根本没人去动。ObjectInputFilter 的 checkInput 方法默认放行一切,等于没开。

我去年帮一个客户做代码审计,发现他们内部RPC框架直接用了Java原生序列化传输请求体。问开发为什么不用Protobuf或JSON,回答是“历史遗留,改不动”。这种场景下,反序列化漏洞不是会不会触发的问题,而是攻击者想不想打的问题。内网横向移动时,一个反序列化点就能拿下整个域。

防御手段其实不复杂。第一,能不用原生序列化就别用,JSON、Protobuf、Avro 都比它安全。第二,如果必须用,上白名单过滤,只允许业务需要的类。第三,升级依赖库,Commons Collections 3.2.2 之后修复了 InvokerTransformer 的序列化问题,但老版本仍在大量系统中运行。第四,别信“内网安全”那套,攻击者进了内网,反序列化就是最快的提权路径。

有个细节值得玩味:很多漏洞扫描器对反序列化的检测是发一个恶意序列化 payload,看目标是否回显或延时。这种检测方式误报率不低,因为有些中间件会捕获异常但不执行命令。真正可靠的检测还是靠代码审计和流量分析——看有没有 readObject 调用,看传输的字节流是不是 AC ED 00 05 开头。后者是Java序列化流的魔数,抓包时一眼就能认出来。

反序列化漏洞的本质是信任边界问题。你信任了来自网络的字节流,字节流里藏着攻击者的对象图。Java 的序列化机制没有做任何完整性校验,这是原罪。JEP 290 是补丁,不是解药。真正的解药是别把不可信数据丢进 ObjectInputStream。这话听起来像废话,但每年还有新的反序列化 CVE 冒出来,说明很多人没当回事。

访客,请您发表评论:

© 2026. sitemap