
开源日志框架 Apache Log4j2 最近又被安全研究者挖出一处潜藏的问题。编号 Log4j2 #4255 的缺陷指向一个相当隐蔽的攻击路径——在特定部署场景下,攻击者有机会绕过反序列化白名单机制,进而实现远程代码执行。这一发现让不少依赖该组件的企业安全团队绷紧了神经。
问题的根源藏在 Log4j 的 FilteredObjectInputStream 这个类里。它的设计初衷是限制反序列化过程中能加载哪些 Java 类,相当于给日志事件接收端加了一道门禁。然而这道门禁存在一个被忽视的盲区:白名单里包含了 java.rmi.MarshalledObject,而这个类本质上是一个"容器",可以把另一个序列化对象打包成不透明的字节数组存进去。

研究者发现,外部对象能堂而皇之地通过 Log4j 的白名单检查,同时把恶意内容藏在内部。当 Log4j 后续调用 MarshalledObject.get() 方法时,Java 会启用一个全新的、未经 FilteredObjectInputStream 过滤的 ObjectInputStream 来反序列化嵌套载荷。换句话说,最初的允许列表对隐藏在内的对象图完全失效,形同虚设。
整个漏洞链条与 Log4jLogEvent$LogEventProxy 密切相关。这个代理类负责把事件消息塞进 MarshalledObject,反序列化时再自动取出来。攻击者正是利用这个机制,精心构造恶意的序列化 Log4j 事件,发送给存在缺陷的接收端,触发目标类路径上已有的 gadget 链执行。


GitHub 用户 Dinosn 提交了这份编号 #4255 的报告,并公开了完整的复现实验室。测试环境搭建在 JDK 17 之上,运行 Log4j 2.26.1 版本。实验结果显示,当未经身份验证的 TCP 接收器采用 FilteredObjectInputStream 处理数据时,嵌入 MarshalledObject 的恶意载荷成功触发了代码执行。更值得注意的是,借助 Commons Collections 3.2.1 的 gadget 链,攻击者无需在受害者系统上额外部署类文件即可完成利用。
不过需要澄清的是,这个漏洞和当年轰动一时的 Log4Shell 并非同一回事。它没法像 Log4Shell 那样,简单往应用日志里塞一段恶意字符串就能触发。利用条件相对苛刻,需要满足几个前提:应用必须对外暴露一个能接收序列化 Log4j 事件的接收器,处理流程得走 FilteredObjectInputStream,而且目标环境里还得存在可用的 Java 反序列化 gadget 链。

Apache 官方在安全指南里也做了说明,当前 Log4j Core 的生产代码通常不会反序列化来自套接字、队列或其他外部来源的数据。FilteredObjectInputStream 被定位为纵深防御工具,而非牢不可破的安全边界。项目方明确提醒,应用层不应该对不受信任的日志事件流执行反序列化操作。
对于企业安全团队来说,眼下最实际的行动是排查遗留系统里那些还在使用序列化 Log4j 事件接收器的老旧组件,尤其是基于早期套接字桥接模式、且未做身份校验的网络服务。及时梳理资产清单,确认是否存在暴露面,是降低风险的第一步。如果业务确实依赖相关功能,建议评估替代方案或增加额外的身份验证与输入校验层,避免把反序列化接口直接暴露在公网可达的位置。


从更宏观的视角看,这次事件再次印证了 Java 反序列化攻击的顽固性与隐蔽性。即便框架层面引入了白名单过滤,一旦允许列表里混入了"特洛伊木马"式的容器类,整个防护体系就可能被单点突破。安全建设从来不是堆砌工具就能一劳永逸,持续跟踪组件更新、保持对攻击面的清醒认知,才是应对这类供应链安全风险的治本之策。

683

被折叠的 条评论
为什么被折叠?



