Log4j2 FilteredObjectInputStream反序列化RCE漏洞分析与绕过实践

发布时间:2026/9/16 6:34:27

Log4j2 FilteredObjectInputStream反序列化RCE漏洞分析与绕过实践 Log4Shell那波风波过去之后我一直在跟Log4j2的各种补丁较劲。说实话刚开始看到官方引入FilteredObjectInputStream的时候我第一反应是“终于开始认真防反序列化了”但等我真正把它的过滤逻辑扒开一看心里又凉了半截——黑名单思路在反序列化这个战场上几乎注定要被绕过。这篇文章就围绕Log4J2的FilteredObjectInputStream RCE漏洞分析展开讲清楚这条防线是怎么设计的、为什么不够用、以及实际利用和排查时你要盯住哪些点。无论你是做安全研究、搞SDL安全评审还是单纯负责公司中间件维护的运维只要你的服务里还躺着Log4j2都值得花十分钟把这篇文章看完。1. 从Log4Shell到FilteredObjectInputStream这条防护线的由来1.1 日志库为什么会成为反序列化入口很多人在Log4Shell之前根本不会把日志库和反序列化联系到一起但Log4j2确实一直存在这个攻击面。最典型的入口就是ObjectMessageLogger直接接收一个Object对象并把它包装成消息这个对象在后续处理、传输、存储时很可能经过Java原生序列化和反序列化。另外一个更大的入口是SocketAppender、JMSAppender、JMX这类网络组件服务端收到序列化字节流后要用ObjectInputStream读出来读的过程就是在反序列化。问题在于Java反序列化本身就是一类高风险的“上帝操作”攻击者只需要找到一个readObject触发链就能在没有任何认证的情况下让服务端执行任意代码。而Log4j2作为日志组件几乎存在于每一个Java应用中只要某一条日志链路里出现了可被攻击者控制的序列化数据RCE就只是gadget chain选型的问题了。Log4Shell漏洞最火的时候大家关注的重点是JNDI lookup的表达式注入通过${jndi:ldap://...}这种字符串直接触发远程类加载。但在官方把JndiLookup移除、把lookup机制默认关闭之后攻击者并不会就此收手——他们把目光转向了Log4j2里残存的反序列化入口。FilteredObjectInputStream正是在这种背景下被加到log4j-core里的目的是给反序列化过程加一层安全过滤。1.2 补丁演进的大致时间线这里简单捋一下Log4j2围绕漏洞出现的几个关键版本节点方便后面讲FilteredObjectInputStream时有共同的上下文。log4j 2.14.1及更早版本存在JNDI lookup的RCE问题也就是Log4Shell的基础版本。log4j 2.15.0-rc2官方开始限制JNDI的远程加载同时默认关闭了lookup功能。log4j 2.16.0动作最大的一版移除JndiLookup类在默认消息转换和网络反序列化场景里引入FilteredObjectInputStream做类过滤。log4j 2.17.0继续扩充FilteredObjectInputStream的阻断名单压缩可用的gadget chain空间。从这些版本动作能看出官方是很清楚“Log4Shell重启了Log4j反序列化这个攻击面”的但FilteredObjectInputStream本质上是对已发生漏洞的被动响应。它把已知的恶意类拒之门外却没有解决“不可信类数据进入Java反序列化流程”这个根因。2. FilteredObjectInputStream的过滤机制到底做了什么2.1 过滤器的工作原理FilteredObjectInputStream和其他安全反序列化包装类的思路类似它继承自ObjectInputStream重写了resolveClass方法。Java反序列化在读取流中的每个对象时都要靠resolveClass把类描述符解析成真正的Class对象FilteredObjectInputStream就在这一步做拦截。protected Class? resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String className desc.getName(); if (blockList.contains(className)) { throw new InvalidClassException(Unauthorized deserialization attempt, className); } return super.resolveClass(desc); }这段逻辑本身不难理解反序列化过程每遇到一个类就去匹配名单命中直接抛异常。但请注意它拦截的是“流中声明出来的类名”而不是“最终会加载到内存里的类”。这个区别在后面的绕过思路里非常关键Java动态代理、反射调用、类加载器配合起来经常能让真正危险的类不出现在流描述符中。2.2 黑名单覆盖了哪些类黑名单的具体内容在不同版本有差异但核心目标很明确先把已知的ysoserial gadget chain常用类封死。以2.16.0和2.17.0为例重点盯防的对象大致包括org.apache.commons.collections.functors.InvokerTransformerorg.apache.commons.collections4.functors.InvokerTransformerorg.apache.commons.collections.functors.InstantiateTransformerorg.apache.commons.collections4.functors.InstantiateTransformerorg.codehaus.groovy.runtime.ConvertedClosureorg.codehaus.groovy.runtime.MethodClosureorg.springframework.beans.factory.ObjectFactorycom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImplcom.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter这几组类基本涵盖了当时最流行的CommonsCollections链、Groovy链、Spring链和TemplatesImpl字节码载体。如果你平时用ysoserial跑过实验看到这些名字应该很眼熟。但黑名单天生有个问题它建立在“官方已知攻击链”的基础上而社区的研究速度永远比厂商快。官方今天封了一个InvokerTransformer明天大家就能翻出TransformUtil、PropertyDescriptor、动态代理组合出来一条新链。黑名单防线的最大弱点不在实现细节而在判断逻辑本身只要能绕开类名检查防线就等于失效了。2.3 过滤触发的真实场景FilteredObjectInputStream并不是Log4j2里所有反序列化操作都会用到的它主要覆盖的是Log4j组件自己控制的输入流。比如log4j的SocketServer接收日志消息时或者某些ObjectMessage需要从网络字节流恢复对象时它会用这个包装类来读。这意味着判断一个Log4j2服务是否受这条防线保护不能只看版本号还要确认具体的入口是不是走FilteredObjectInputStream。我自己在排查中就踩过这种坑以为升级到2.16.0就万事大吉结果应用的某个自定义Appender根本没走这个包装类直接裸用ObjectInputStream读数据等于补丁没打上。3. 绕过思路与RCE利用链的构造逻辑3.1 黑名单的固有缺陷做安全的人常讲一句话黑名单是“已知威胁”的围墙白名单才是“未知威胁”的闸门。Java反序列化恰好是黑名单最吃不消的场景原因有三点。第一反序列化链可以无限组合。ysoserial里一条链常常涉及七八个类的嵌套调用黑名单封几个核心类攻击者换一个入口类就能重新打通。第二Java的反射和动态代理机制让“类加载”和“类名出现”解耦攻击者可以构思一种不直接在流里写敏感类的payload。第三不同版本JDK自带的内部类一直在变官方想追齐所有可能的gadget来源根本不现实。FilteredObjectInputStream遭遇的困境正是这种黑名单思路的缩影。在分析绕过时比提供一条现成PoC更有价值的是理解它的筛选粒度它只看“被序列化对象的类名”却管不了“某个允许对象内部构造时通过间接方式加载了危险类”。3.2 一条经典绕过的构造思路抛开不同版本的黑名单差异我以TemplatesImpl这条最通用的字节码加载关系为例讲讲绕过链条是怎么拼起来的。TemplatesImpl本身是一个能在反序列化后加载自定义字节码并执行的高危类它的绕过价值在于类加载的触发只需要调用getOutputProperties方法而com.sun.org.apache.xalan.internal.xsltc.trax包里的这个类在2.16.0之后可能已经被列进名单。攻击者此时的目标就变成了“找到一个不在黑名单的类它可以反射调用TemplatesImpl的getOutputProperties”。这就有了一条通用链的雏形用PriorityQueue作为反序列化入口它在readObject时会执行元素比较。比较器选择org.apache.commons.beanutils.BeanComparator它可以通过PropertyDescriptor反射调用任意Bean的getter方法。把TemplatesImpl作为BeanComparator的对比对象排序时就会反射调用TemplatesImpl.getOutputProperties。getOutputProperties加载恶意字节码完成RCE。这里核心的绕过点就是BeanComparator不在FilteredObjectInputStream的黑名单里它承担了“借刀杀人”的角色。即使TemplatesImpl被ban只要还能找到另一个字节码载体或另一个可以反射调用的入口这条链就能换个马甲继续跑。3.3 和CTF里常见的RCE绕过有什么异同最近在不少CTF群里看到大家在刷命令注入、RCE绕过的题目比如空格绕过、管道符、base64编码、黑名单关键字替换之类。这些Web层面的RCE绕过和Java反序列化绕过底层其实是同一个思维先搞清楚过滤器的规则再找到规则外的执行通道。不过差别在于Web层RCE过滤通常是针对命令字符串做正则或关键字匹配而Java反序列化的过滤针对的是类名和对象流结构攻击者不需要在payload里写命令原文只需要构造好对象关系即可。这让你在排查时更难从日志字符串里发现问题因为请求体往往是一长串二进制乱码不做协议解码根本看不到里面是什么类。4. 本地实验环境复现与观察4.1 搭建一个最简实验环境纸上谈兵没意思我建议你在隔离环境里把这个过程完整跑一遍既安全又能加深理解。我用到的环境组合和思路是这样的仅供参考JDK版本8u202之前的版本避免遇到高版本对TemplatesImpl的限制。依赖版本log4j-core 2.16.0注意要和log4j-api配套。触发入口启动一个基于Log4j SocketServer或TcpSocketServer的接收端让它用FilteredObjectInputStream读取网络流。gadget依赖commons-beanutils 1.9.4、commons-collections 3.2.2这是构造BeanComparator链需要的基础库。你可以在本机用两个进程模拟一个进程作为攻击者发送构造好的序列化payload另一个进程作为“受害服务”接收并反序列化。整个过程务必断网控制好运行环境避免真实机被打穿。4.2 构造payload时的关键细节payload构造通常直接改ysoserial的CommonsBeanutils1模板就能出来核心工作就三件事把恶意字节码封装进TemplatesImpl的_bytecodes字段这部分字节码是一个继承AbstractTranslet的恶意类其静态代码块或构造函数里放要执行的命令。用BeanComparator和PriorityQueue构造触发关系确保反序列化PriorityQueue时compare操作能一路调用到TemplatesImpl.getOutputProperties。序列化整个对象发送给目标端口。我在实际调试时最喜欢用序列化数据查看工具逐个检查流中的类描述符顺序。你会看到FilteredObjectInputStream拦截时的特征抛出InvalidClassException日志里记录“Unauthorized deserialization attempt”和对应的类名。如果哪一步没有触发过滤基本上就是gadget chain中途用了黑名单外的类完成了同样的调用路径。4.3 观察堆栈和过滤日志复现完成后受害服务端的堆栈应该是从ObjectInputStream.readObject开始一路走到FilteredObjectInputStream的resolveClass或TemplatesImpl的相关调用。这里有两种观察结果对应的结论完全相反如果你看到InvalidClassException说明FilteredObjectInputStream成功拦下了某个危险类但你的payload还没有真正绕过黑名单。如果你看到命令执行结果比如弹出了计算器、生成了临时文件说明整个链路的类名都没有被过滤FilteredObjectInputStream的防护在这里失败了。我建议把受害服务端的内存和堆栈dump下来做个快照方便反复验证不同gadget chain在过滤器面前的表现。这个习惯在我研究Weblogic、Jackson等其他反序列化漏洞时也帮了很大忙。5. 加固清单与常见问题排查5.1 快速判断自己的应用是否受影响结合我踩过的坑先给你一份排查优先级第一步查版本。log4j-core低于2.17.0的都要视为不安全2.16.0虽然有FilteredObjectInputStream但名单不足。第二步查入口。确认应用是否使用SocketAppender、JMSAppender、自定义Appender是否把网络输入直接交给Log4j处理。第三步查配置。确认formatMsgNoLookups是否已经显式设为true避免lookup机制从其他入口复活。第四步查依赖。看看应用里是否带有commons-beanutils、commons-collections、groovy、spring-core等常见的gadget依赖这些会放大攻击面。5.2 常见拦截失败原因我见过不少团队照着重现文章操作但payload始终弹不回来从头排查后原因集中在几类现象可能原因处理建议发送后无任何日志目标端口根本不是Log4j接收服务确认网络链路和端口对应关系抛出InvalidClassException某个链类被FilteredObjectInputStream拦截换gadget chain或更换入口类反序列化报错ClassNotFound目标环境缺少需要的gadget依赖库在目标环境确认依赖列表有连接无命令执行JDK版本过高限制了TemplatesImpl换JDK版本或改用其他字节码载体命令执行时断时续字节码的Translet类没有正确继承或方法签名不对参考ysoserial模板检查恶意类结构5.3 生产环境的加固建议版本升级始终是第一选择但别只升一个log4j-core就结束log4j-api、slf4j绑定层都要一起看。有条件的团队建议在应用服务器上配合JEP 290设置全局反序列化过滤器把不可信来源的类限制在白名单范围内。JEP 290不能解决所有问题但能大幅压低攻击面。再一个容易忽略的点生产环境尽量不要直接打ObjectMessage给外部数据尤其是来自网络、消息队列、用户请求的对象。如果业务非要传对象优先改用JSON、Protobuf这类结构明确、无多态机制的格式彻底绕开Java原生反序列化这个雷区。RASP类产品可以作为兜底但不要当作主要防线毕竟它们同样需要识别和阻断未知gadget chain。5.4 关于CVE-2021-44832的延伸提醒FilteredObjectInputStream只是反序列化入口的一道闸而Log4j2的其他攻击面在补丁之后依然存在。CVE-2021-44832就是一个典型例子它影响2.17.0之前版本利用链落在JDBCAppender上如果攻击者能控制Log4j配置就可以通过指定恶意的JDBC数据源地址让Log4j在启动JDBCAppender时加载远程类并执行代码整个过程和FilteredObjectInputStream的黑名单毫无关系。这类“配置驱动”的漏洞提醒我们安全加固不能只盯防护组件的实现还要把配置文件的完整性保护提上日程。在我接触过的不少事故里攻击者根本没费劲去绕过滤器而是直接拿到了配置文件或JMX接口的写权限从侧门打了进来。关于整个分析过程最后分享一点个人体会FilteredObjectInputStream这个案例让我最深刻的点不是某个类被绕过而是它印证了Java反序列化防护的一个死循环只靠黑名单封堵已知类永远慢半拍。日常做安全评审时我更建议大家把精力花在“入口缩减”和“结构替换”上而不是跟攻击者比拼谁手里的类名列表更全。最后再分享一个小技巧分析这类payload时先用serializationdumper把序列化流的类描述符完整导出再对照黑名单看一遍你会非常直观地看出过滤器到底截断了哪一层。对防御者来说这种可视化的分析能力有时比战场上多上一条能打的链子更有意义。
延伸阅读

更多相关文章

2026/9/16 6:34:27

Python在金融科技领域的核心应用与实战技巧

1. Python为何成为金融科技领域的首选语言在华尔街投行和对冲基金的交易大厅里,Python已经悄然取代了传统的Excel和SAS,成为量化分析师和金融工程师们的标准配置。这种转变并非偶然——根据2023年Wilmott杂志的行业调查,超过78%的金融机构在核…

2026/9/16 6:29:26

Zemax混合式非序列建模:序列与非序列协同仿真原理与实战

1. 什么是Zemax混合式非序列模拟?它到底解决了什么实际问题?Zemax混合式非序列模拟,不是某种新发布的软件版本,也不是一个独立模块的代号,而是光学工程师在真实项目中反复摸索、权衡后形成的一套工程化建模策略。简单说…

2026/9/16 6:29:26

基于Django的学业预警系统开发实战:ORM聚合查询与预警规则实现

简介:面向高校毕业设计场景的Python学业预警系统完整项目包,覆盖管理员与学生双端功能模块,包含菜单管理、预警分析、学生信息/成绩管理、用户权限管理以及个人信息与学习计划等模块,系统基于Django框架与MySQL数据库构建&#xf…

2026/9/16 7:24:29

【人工智能每日精选】AI 帮我看见孩子学数学的隐藏路径

很多孩子不是“不会学”,也不是“不够努力”,而是他们的大脑在形成数学表征时,可能走了一条更慢、更容易混淆的路径。 过去谈数学学习障碍,我们很容易停在分数上:做题慢、准确率低、加减法容易错。但分数只告诉我结果,不告诉我过程。真正值得追问的是:孩子在看到一个算…

2026/9/16 7:24:29

Arm Model Selector:边缘AI模型选型,延迟与内存占用提前预知

做边缘端AI这一年多,我最大的体会是:选模型比训模型更折磨人。服务器上精度漂亮的模型,真扔到Arm开发板上,要么延迟直接飙到几百毫秒,要么内存占用超出硬件规格,启动就崩。最近Arm官方放出了一套针对硬件优…

2026/9/16 7:24:29

HTTP/HTTPS协议实战解析:从报文结构到状态码排查技巧

如果你曾经在终端里看到过一串报错,比如502 bad gateway或者404 not found,第一反应是去改服务器配置还是去百度?我见过太多同行卡在这一步——不是不会调,而是看不懂 HTTP 协议在说什么。HTTP、HTTPS、请求头、响应头、状态码、数…

2026/9/16 7:24:29

手把手实现AXI4-Lite从零到可调试外设

1. 这不是“又一篇AXI协议教程”,而是你真正能跑通的第一个AXI工程如果你刚在Vivado里点开一个带AXI接口的IP核,看到那十几根信号线——AWVALID、AWREADY、WVALID、WREADY、BVALID、BREADY、ARVALID、ARREADY、RVALID、RREADY……然后盯着AXI4-Lite地址映…

2026/9/16 7:24:29

JavaScript内存模型:原始类型与引用类型的本质区别

1. 这不是语法手册&#xff0c;是帮你绕开JavaScript第一道墙的实战指南你打开一个HTML文件&#xff0c;写上<script>alert(1)</script>&#xff0c;页面弹出数字1——恭喜&#xff0c;你已经“运行”过JavaScript了。但真正卡住绝大多数零基础学习者的&#xff0c…

2026/9/16 7:19:29

RoboMaster硬件调试实战手册:GD32H7电源与CAN故障排查指南

1. 这份讲义到底在讲什么&#xff1a;不是教材&#xff0c;是硬件工程师的“现场作业手册”“Robomaster硬件基础讲义V0.2.1”——光看标题&#xff0c;很多人第一反应是“哦&#xff0c;又是那种PPT式教学材料”&#xff0c;翻两页就搁下了。但我在哈工大电控组带过三届RoboMa…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述&#xff1a;一台黑屏的拯救者Y7000&#xff0c;到底卡在哪一步&#xff1f; 联想拯救者Y7000系列笔记本&#xff0c;从2018年第一代搭载i5-8300H开始&#xff0c;到后来的i7-9750H、i7-10750H、i5-11400H&#xff0c;再到2023年款的R7-7840HS&#xff0c;它始终是学…

2026/9/16 0:04:09

PHP源码部署实战:从环境配置到运行情侣游戏全攻略

简介&#xff1a;这是一套面向情侣互动场景的PHP完整源码&#xff0c;集成情侣飞行棋、真心话大冒险、情趣骰子等玩法&#xff0c;并内置完整分销制度&#xff0c;可自定义多种返佣比例&#xff0c;源码完全开源无加密&#xff0c;支持微信无感自动授权登录与第三方授权&#x…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码