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

发布时间:2026/11/13 13:33:21

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/11/13 9:24:48

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

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

2026/11/12 7:53:21

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

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

2026/11/12 9:17:43

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

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

2026/11/13 13:29:33

工地太忙根本没时间复习考试?即墨考电工证千万别踩坑

工地太忙根本没时间复习考试?即墨考电工证千万别踩坑 工地太忙根本没时间复习考试?这几乎是每个刚接触【即墨考电工证】的新手都会遇到的问题。你可能刚从学校毕业,或者转行进入建筑、电力行业,但面对电工证考试,脑子里一片空白,不知道从哪儿下手。别慌…

2026/11/13 13:29:33

高压电工作业证都怎么考才稳过?实操考试心里没底怕挂科

高压电工作业证都怎么考才稳过?实操考试心里没底怕挂科 实操考试心里没底怕挂科,尤其是高压电工作业证都这门硬骨头,不少考生在报名前就焦虑不已。其实,只要掌握好方法、了解流程,高压电工考试并不是难以跨越的鸿沟。本文将从商丘初次报考人员的视角出发…

2026/11/13 13:29:33

一汽要的电工证实操考试心里没底怕挂科?官方报名入口在这!

一汽要的电工证实操考试心里没底怕挂科?官方报名入口在这! 实操考试心里没底怕挂科,这几乎是每个准备报考电工证的人的真实写照。尤其是一汽这类对电工证要求极高的企业,对证书的含金量、实操能力、甚至考试细节都盯得死死的。如果你也正准备报考,或者正…

2026/11/13 13:29:33

电工证焊工证哪个简单?值不值得考?实操考试心里没底怕挂科

电工证焊工证哪个简单?值不值得考?实操考试心里没底怕挂科 实操考试心里没底怕挂科,这几乎是所有想考特种作业操作证的人共同的担忧。电工证和焊工证哪个更简单?值不值得考?这是很多在特种作业行业打拼的人最关心的问题。如果你也在犹豫,别急,看完这篇…

2026/11/13 13:24:31

江夏在哪里报考电工证 全国通用证书怎么复审不丢饭碗

江夏在哪里报考电工证 全国通用证书怎么复审不丢饭碗 证书过期了不知道怎么复审延期,很多人突然发现手里那张电工证已经失效,连带的是一份收入的骤降。特别是在江夏,像你这样依赖电工证吃饭的人,如果连复审流程都不清楚,后果可能就是被清退、降薪,甚至…

2026/11/12 20:35:13

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/13 0:01:06

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了 你是不是也像我一样,第一次听说“高压电工证”这个名词,就感觉一头雾水?其实很多人都跟我一样,不知道去哪报名、怕被中介坑,结果花了冤枉钱还考不上。今天我就从一个在商丘培训过的学员角度,…

2026/11/13 0:01:06

黎里考电工证在哪里值不值得考

黎里考电工证在哪里值不值得考 之前考的证在外省能不能转过来?这是很多在外地工作、准备回老家发展的朋友最关心的问题。特别是在黎里地区,很多从事电力相关工作的朋友,都面临这样一个难题: 外省的电工证能否在本地使用?值不值得考?…

2026/11/13 0:01:06

毕节哪里考电工证 怎么报名学历不高也能上手

毕节哪里考电工证 怎么报名学历不高也能上手 你是不是也和我一样,学历不高,想着考个电工证,但又担心自己条件不够,怕报不上名?其实不然,只要符合条件,学历不高也能考电工证。今天就来聊聊【毕节哪里考电工证】这个问题,还有怎么报名,让你一步到位不…

2026/11/12 22:10:13

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/13 12:14:39

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

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

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

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