Log4j2FilteredObjectInputStream绕过漏洞深度分析

admin 2026-08-27 05:28:25 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文档深度分析了Log4j2FilteredObjectInputStream绕过漏洞(CVE-2026-XXXX),影响2.11.0至2.26.1版本。漏洞核心在于FilteredObjectInputStream仅检查顶层类描述符,而Log4jLogEvent的message()方法调用MarshalledObject.get()时会创建不受过滤的ObjectInputStream,导致攻击者可通过包装恶意gadget实现远程代码执行。建议立即移除MarshalledObject白名单或改用过滤序列化通道。 综合评分: 88 文章分类: 漏洞分析,安全工具,安全开发,应用安全,解决方案


Log4j2 FilteredObjectInputStream 绕过漏洞深度分析

洛米唯熊

2026年8月26日 15:00 福建

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

这是一个严重的远程代码执行(RCE)漏洞

影响 Log4j 2.11.0 至 2.26.1 版本。


漏洞概要

| 属性 | 详情 | | — | — | | 漏洞ID | GitHub Issue #4255 | | 报告者 | U-Sec (Wujie Security) | | 漏洞类型 | Java 反序列化过滤器绕过 | | 影响版本 | log4j-api 2.11.0 – 2.26.1 / log4j-core 2.8.0 – 2.26.1 | | 影响范围 | 所有Java版本 (Java 8 及以上) | | 严重等级 | 极高 (RCE) | | 报告日期 | 2026年8月24日 |


技术原理详解

核心漏洞链条

这个漏洞涉及三个环节的缺陷配合:

位置:log4j-api/util/internal/SerializationUtil.java:81问题:REQUIRED_JAVA_CLASSES 包含 java.rmi.MarshalledObject

问题所在:FilteredObjectInputStream 在其 resolveClass() 方法中只验证顶层类描述符,无法检查嵌套在 MarshalledObject 内部的 objBytes 字段中的序列化数据。

位置:java.rmi.MarshalledObject.get()特性:创建一个全新的、完全不受过滤的 ObjectInputStream

当调用 MarshalledObject.get() 时,它会:

  • 构造一个 新的纯 ObjectInputStream(不是 FilteredObjectInputStream
  • 直接反序列化内部的 byte[] 内容
  • 完全绕过过滤机制
位置:log4j-core/impl/Log4jLogEvent.java:1265-1274代码:private Message message() {    if (marshalledMessage != null) {        try {            return marshalledMessage.get();  // 无过滤的新 ObjectInputStream        } catch (final Exception ex) { /* 忽略异常 */ }    }    return new SimpleMessage(messageString);}

关键点:LogEventProxy 在反序列化时会自动调用 readResolve() → message() → marshalledMessage.get(),自动触发不受保护的反序列化。


攻击链详解

攻击步骤

  1. 创建恶意对象    – 攻击者使用任意 Java 反序列化 gadget(如 CommonsCollections、JNDI 等)    – 对象 不需要实现 Message 接口    – 对象 不需要在 Log4j 白名单中
  2. 包装成 LogEventProxy java    final Log4jLogEvent event = Log4jLogEvent.newBuilder()        .setLoggerName("attacker")        .setLevel(Level.INFO)        .setMessage(new MessageShell(gadget))  // gadget 被包装        .build();    final LogEventProxy proxy = new LogEventProxy(event, false);    // 序列化 proxy
  3. 发送到日志接收器    – 目标:任何使用 FilteredObjectInputStream 的日志接收器    – 典型受害者:      – ObjectInputStreamLogEventBridge(官方示例)      – vertigo-analytics-server 的 createSerializedSocketServer      – Log4j 2.14.x 及更早的 TcpSocketServer
  4. 自动执行 接收端代码:    try (ObjectInputStream in = new FilteredObjectInputStream(socket.getInputStream())) {        final LogEvent event = (LogEvent) in.readObject();    }    ↓    触发 LogEventProxy.readResolve()    ↓    调用 message()    ↓    执行 marshalledMessage.get()(无过滤)    ↓    gadget.readObject() 执行 → RCE
  5. 隐蔽性    – 反序列化异常被 catch 块吞掉    – 日志接收器继续正常处理    – 攻击者发送的 payload 进入下游 appender

漏洞验证 PoC 结果

对照组测试(直接发送恶意对象)

输出:InvalidObjectException: Class is not allowed for deserialization: poc.EvilMessage结果:✓ 被正确拒绝

攻击测试(通过 LogEventProxy 包装)

[receiver] bound to 0.0.0.0 (all interfaces), no auth, port 4563[receiver] connection from /[attacker] single fire-and-forget write: 1356 bytes - done[!!] GadgetOnly.readObject() EXECUTED - no Message iface, no allowlist entry[receiver] processed event: benign message 结果:✓ 恶意对象成功执行,接收器无错误提示

影响范围

远程代码执行(RCE)

  • 所有接收序列化日志事件的服务 都面临 RCE 风险:

  • 默认不使用 TLS 或身份验证

  • 绑定到所有网卡(0.0.0.0

  • 监听网络端口

不含 Gadget 库的情况

即使没有 Commons Collections 等库,攻击者仍可:

  • 资源耗尽 DoS:构造超大对象图(object-graph bombs)
  • 日志注入:将攻击者控制的内容注入下游日志输出

受影响的官方组件

  • log4j-core

    中的 TcpSocketServer.createSerializedSocketServer()(≤ 2.14.x)

  • 官方示例中的 ObjectInputStreamLogEventBridge

  • 第三方 vertigo-analytics-server


根本原因分析

| # | 位置 | 缺陷 | | — | — | — | | 1 | SerializationUtil.java:81 | REQUIRED_JAVA_CLASSES 包含 java.rmi.MarshalledObject | | 2 | FilteredObjectInputStream.java:66-72 | resolveClass() 只检查顶层描述符,无法看穿 objBytes payload | | 3 | Log4jLogEvent.java:1134 | 定义了 private MarshalledObject<Message> marshalledMessage 字段 | | 4 | Log4jLogEvent.java:1265-1274 | message() 方法调用 marshalledMessage.get()(无过滤)且吞掉异常 |


修复建议

选项 A(最小化,推荐)

改动两个文件:

  1. 移除 java.rmi.MarshalledObject 白名单 文件:SerializationUtil.java &nbsp; &nbsp;操作:从 REQUIRED_JAVA_CLASSES 中删除 MarshalledObject
  2. 改用已过滤的序列化方式 java &nbsp; &nbsp;// 不使用 MarshalledObject,改用 SerializationUtil 的被过滤通道: &nbsp; &nbsp;// writeWrappedObject() / readWrappedObject() &nbsp; &nbsp;// (与 ObjectMessage 采用相同方式) &nbsp; &nbsp; &nbsp; &nbsp;// 序列化时:writeWrappedObject(message) &nbsp; &nbsp;// 反序列化时:readWrappedObject() 返回 byte[] 并通过 FOIS 过滤

优点:

  • 完全移除无过滤的 get() 调用
  • 支持 Java 8(JEP 290 过滤器不可用)
  • 简单且可靠

选项 B(结构化)

迁移到JEP 290ObjectInputFilter,该过滤器在 JDK 9+ 上可以穿透 MarshalledObject。

缺点:需要 JDK 9+,改动较大。


为什么这个漏洞很特殊

报告者强调了这与一般的”操作员误用”不同:

  1. 触发是自动的:Log4j 核心自己序列化 LogEventProxy,自己触发反序列化
  2. 不在威胁模型内:用户无法预防,因为过滤器本身有缺陷
  3. 完整 gadget 目录适用:payload 不受任何限制(不需实现 Message、不需在白名单中)

时间线

  • 2026年8月24日:U-Sec 提交安全报告
  • 报告方式:GitHub Issue(因为仓库未启用私密安全公告)
  • 协调:请求安全邮箱 [email protected] 和跟踪号

PoC 代码在修复发布后或 90 天后才会公开。


这是一个设计缺陷而非配置问题,任何运行 Log4j 2.11.0 – 2.26.1 的日志网络接收服务都应立即升级。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:洛米唯熊 《Log4j2 FilteredObjectInputStream 绕过漏洞深度分析》

评论:0   参与:  0