文章总结: 本文探讨Java反序列化漏洞的学习方法,提出不应死记硬背具体攻击链,而应建立五层结构模型(Source→Trigger→Bridge→Propagator→Sink)来理解反序列化过程。作者以CC链为例分析各层组件,并扩展到CB、ROME等链的对比,指出不同链的核心差异在于传播方式。文章建议通过框架化学习提高举一反三能力,在AI时代更应注重理解底层原理而非单纯记忆调用栈。 综合评分: 85 文章分类: 漏洞分析,代码审计,WEB安全,实战经验,安全开发
关于Java中反序列化漏洞的思考
me7eorite me7eorite
Gh0xE9
2026年5月3日 19:12 福建
在小说阅读器读本章
去阅读
问题
刚开始学 Java 反序列化时,很容易被各种链劝退。比如 CC1-CC8、CB、ROME、Hessian、Shiro、Fastjson,每一条链看起来都有很长的调用路径。如果只是按编号去背:
CC1 是怎么调用?有什么限制?
CC2 是怎么调用?有什么限制?
CC6 是怎么调用?有什么限制?
短期看起来好像学了很多,笔记的文件也在增加,收集了很多调用栈,但过一段时间很容易忘。尤其在 AI 时代,直接问一句“帮我总结一下 CC 链”,AI 可以生成一篇很完整的文章,但是问题在于:
- 1. 我真的理解了吗?
- 2. 我能够举一反三吗?
- 3. 我能够检查AI出错的时候吗?
观点
学习反序列化链,不应该只盯着某一条链的完整调用过程,应该思考学习的目的,为的是建立反序列化链的模型。
一些文章常常会读到:Source -> Sink 的写法,但是这个路径太短,不适合学习的时候用,可以参考:
Source -> Trigger -> Bridge -> Propagator -> Sink
Source -> Trigger -> (Bridge Gadget -> Propagator Gadget -> Sink Gadget -> Sink)
这五层分别对应:
- • Source:反序列化时自动执行逻辑的入口。
- • Trigger:Source 自动调用的方法,例如
hashCode、compare、toString、setValue。 - • Bridge:将 Trigger 调用转接到 gadget 链的关键对象。
- • Propagator:继续传播调用的对象。
- • Sink:最终产生危险效果的方法。
这样看一条链时,就不是记一长串方法名,而是判断每一层分别由谁承担,后续了解到 CodeQL 也可以继续利用这个思路。
方法
CommonsCollections 系列最容易让人误解的地方是:看起来 CC1、CC2、CC3、CC4、CC5、CC6、CC7 都是不同的链,但从分层模型看,它们更多是在不同层里换组件,以下以 CC 链中出现的为例:
Source:
- •
AnnotationInvocationHandler:CC1 / CC3 - •
HashMap/HashSet:CC6 / CC3 - •
PriorityQueue:CC2 / CC4 - •
TreeBag / TreeMap:CC4 变体 - •
BadAttributeValueExpException:CC5 - •
Hashtable:CC7
因为高版本 JDK 改了 AnnotationInvocationHandler 的实现,CC1 原来的触发方式不再稳定。所以更换 Source,本质上是在找新的自动调用点,减少对特定 JDK 版本的依赖,不同 Source 会带来不同 Trigger:
- •
HashMap会触发 key 的hashCode - •
PriorityQueue会触发 comparator 的compare - •
BadAttributeValueExpException会触发toString - •
AnnotationInvocationHandler会触发 Map 相关操作
Bridge 和 Propagator(其实还可以细分):
- •
TransformedMap:把setValue/ 写入 value 转成Transformer#transform - •
LazyMap:把get转成Transformer#transform - •
TiedMapEntry:把hashCode/toString转成getValue -> map.get - •
TransformingComparator:把compare转成Transformer#transform
这里要区分一个点: TiedMapEntry 和 LazyMap 经常一起出现,但它们角色不同。
- 1. CC6 :
HashMap#hashcode -> TiedMapEntry#hashcode -> LazyMap#get - 2. CC5 :
BadAttributeValueExpException#toString -> TiedMapEntry#toString -> LazyMap#get简而言之,CC5 和 CC6 的中后段其实一样,只是 Trigger 不一样。
Sink 也可以进行区分,有些类本身不是真正的危险点,而是 “Sink的调用器”,可以称为 Sink Gadget。 例如:
- •
InvokerTransformer:实现反射调用 - •
InstantiateTransformer + TrAXFilter:实现实例化类
真正的危险点是 Real Sink:
- •
Runtime.exec - •
TemplatesImpl#newTransformer - •
TemplatesImpl#defineTransletClasses / defineClass
举个例子: InvokerTransformer 不是最终 Sink,它只是反射调用工具。真正的 Sink 要看它最后调用的是 Runtime.exec,还是 TemplatesImpl#newTransformer。
拓展到 CB 和 ROME
这个模型不只适用于 CC,CB 链也可以分析:
Source:PriorityQueue
Trigger:comparator.compare
Bridge:BeanComparator
Propagator:PropertyUtils.getProperty -> getter
Sink:TemplatesImpl#newTransformer
CB 的重点不是 Transformer,而是 JavaBean 属性访问:
compare -> getProperty -> getter -> sink
ROME 链也类似:
- • Source:HashMa
- • Trigger:hashCode
- • Bridge:EqualsBean / ObjectBean
- • Propagator:ToStringBean -> JavaBean getter
- • Sink:TemplatesImpl#newTransformer
ROME 的关键点是:
hashCode / equals / toString -> JavaBean getter -> sink
所以从 CC 到 CB,再到 ROME,可以看到一个共同思路:
- 1. 反序列化入口自动调用某个普通方法
- 2. 普通方法被 Bridge 实现
- 3. 调用进行传播
- 4. 最后触发危险方法
区别在于中间的传播方式不同:
- • CC 主要围绕
Transformer(如何调用到transform方法) - • CB 主要围绕
PropertyUtils和 getter - • ROME 主要围绕
EqualsBean、ToStringBean、ObjectBean和 getter
结论
AI 可以快速生成大量链路总结,最快速地检索到大量资料,建立一个框架并以最大能力去往框架里补充和完善内容,我认为是提高学习效率的一个方式。 以反序列化链为例,通过对结构进行拆分:
Source -> Trigger -> Bridge -> Propagator -> Sink
后续学新链的时候可以补充这个结构,在遇到某个特殊的 Source/Trigger/Sink 或许可以联想到这个在 XX 是否可用,而不是简单的背诵和调试堆栈。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Gh0xE9 me7eorite me7eorite《关于Java中反序列化漏洞的思考》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论