JBoss反序列化漏洞CVE-2017-7504排查与修复实战指南

发布时间:2026/10/19 11:22:14
JBoss反序列化漏洞CVE-2017-7504排查与修复实战指南 前阵子做例行安全巡检我在一份资产清单里发现一台老应用服务器被标记成“高危”。点开详情一看报警原因是JBoss反序列化漏洞编号CVE-2017-7504。这个编号对做Java中间件安全的人来说并不陌生它属于JBoss历史上那批远程代码执行级别的反序列化漏洞攻击者不需要登录只要往JBoss暴露出去的接口丢一串精心构造的二进制数据就能在服务器上把命令执行掉。接到这种报警第一反应往往是头大JBoss老环境改起来牵一发动全身但漏洞又是必须处理的那种“不修不行”。这篇文章就是我当时处理过程的复盘从漏洞原理、自查方法、临时缓解到长期加固把能直接照做的步骤都整理出来。适合正在搞Java中间件安全巡检、手上有老JBoss要整改或者单纯想把反序列化漏洞原理搞清楚的人看。1. CVE-2017-7504的影响面为什么老JBoss还会中招1.1 我遇到它的具体场景那次巡检目标是一个业务系统的公网入口。漏扫报告里的路径我记得很清楚/invoker/JMXInvokerServlet。端口是8080不显眼但扫描器给出的结论非常直白远程代码执行。我顺手确认了一下这个接口不仅存在而且没有做任何认证限制任何能访问这台服务器8080端口的人都能向它发送数据。也就是说这台机器基本等同于把一扇后门开在公网上就差把利用方式贴出来了。后续排查也印证了这一点系统管理员已经不知道这台JBoss具体是谁部署的只记得“很多年前就在跑”。业务还在用没人敢动。这应该是很多老系统的常态——中间件的安全风险往往不是新漏洞带来的而是历史包袱一直在。1.2 受影响版本与同类漏洞确认先说结论CVE-2017-7504影响的不只是一个具体版本而是一类使用到HTTPInvoker组件的老JBoss产品线。常见的受影响范围大致如下版本系列受影响情况处理建议JBoss AS 4.x / 5.x / 6.x社区版已停止维护尽快迁移到WildFly或受支持版本JBoss EAP 5.x受影响安装官方补丁并规划版本升级JBoss EAP 6.x受影响升级到修复后的6.4.x补丁版JBoss EAP 7.x / WildFly默认配置已去除相关Servlet仍需检查历史遗留配置需要多说一句CVE-2017-7504本质上是JBoss的HTTPInvoker组件在反序列化时缺少类型限制。它在业界常和同一年曝出的CVE-2017-12149放在一起讨论因为两者的根源高度相似都属于“老JBoss反序列化家族”。做安全整改时不要只盯着一个编号把老JBoss上的同类入口一起过一遍效果会好很多。有些系统表面上只报了7504实际检查时还能看到其他反序列化路径甚至同时存在多个漏洞。1.3 为什么现在还能听到JBoss中招因为JBoss AS 4/5/6太老了。老到很多部署它的人已经离职老到它依赖的很多组件库已经多年没有更新老到项目负责人说“只要不出事就别动”。而反序列化漏洞利用起来又特别稳定早几年针对JBoss的安全研究非常多攻击工具链非常成熟。对企业来说这意味着一个问题只要一台带漏洞的老JBoss暴露到公网被攻破只是时间问题。修复的意义不在于“赶紧把这个漏洞堵上”而在于把这类无主资产的暴露面彻底收掉。这也是后面第五部分要专门讲体系建设的原因——单点打补丁永远追不上漏洞披露的速度。2. 漏洞原理拆解从Java序列化到远程命令执行2.1 序列化与反序列化Java对象如何变成字节流先做一个基础铺垫。Java的序列化机制是把内存里的对象变成一段字节流可以写入文件、数据库或者通过网络发送到另一台机器。对端拿到字节流之后再通过反序列化把字节还原成对象。常见代码大概是这样// 发送端把对象写成字节流 ObjectOutputStream out new ObjectOutputStream(socket.getOutputStream()); out.writeObject(user);// 接收端把字节流还原成对象 ObjectInputStream in new ObjectInputStream(socket.getInputStream()); Object obj in.readObject();在还原对象的过程中Java会调用对象自身的readObject()方法而这个方法允许被类开发者重写。如果传入的对象类型完全由网络请求控制并且这个类以及它依赖的库中存在可以被拼接利用的“危险方法序列”攻击者就能让服务端在反序列化时执行到任意操作。打个比方你收到一个快递快递单上写的是“工艺品”但拆开包裹后里面的装置会自动展开把零件弹到你脸上。而你自始至终没有检查盒子里的东西是谁寄的、内部是什么结构。JBoss的问题就是它在公网端口上痛快地帮忙签收了一个又一个这样的包裹。2.2 JBoss的HTTPInvoker问题在哪JBoss为了实现远程管理把JMX调用和EJB调用封装成序列化对象再放到HTTP请求体里传输。对应的入口就是JMXInvokerServlet、EJBInvokerServlet这类Servlet业界一般统称为HTTPInvoker组件。服务端收到请求后直接把请求体交给ObjectInputStream.readObject()来还原调用参数。问题出在这里这个读取过程没有对类型做白名单或黑名单限制也没有校验数据来源的合法性。攻击者把一段精心构造的gadget chain放进序列化字节流服务端就糊里糊涂地帮助执行了里面的危险逻辑。一句话总结JBoss把反序列化能力直接当成了HTTP服务的默认出口而这个出口不设防。2.3 攻击链路的“拆解式”走读一个完整攻击流程站在防御方视角可以拆成五个环节攻击方扫描发现8080/invoker/JMXInvokerServlet等路径可访问攻击方用工具生成恶意序列化数据数据内容包含一条gadget chain攻击方直接把二进制数据POST到该接口JBoss的Servlet层把HTTP请求体交给ObjectInputStream.readObject()readObject()触发链条最终执行攻击者下发的命令。这五步里第1步靠收敛暴露面来解决第2、3步靠WAF和反序列化过滤器来缓解第4、5步只能靠升级或阻断入口来根除。知道链路的好处是你可以判断自己的加固措施做在哪个环节而不是碰运气式地打补丁。在隔离测试环境我用公开的ysoserial工具验证过这条链路跑的是一个无副作用的探测命令比如打印当前测试用户。生产环境不建议做这类验证容易引发告警而且万一操作不当等于自己把漏洞验证成了真实利用。3. 修复与加固实操临时缓解、升级与纵深防御3.1 自查确认你的JBoss是否存在这个入口修漏洞之前先确认自己手上的JBoss到底有没有这个入口。按照下面四步过一遍基本能判断清楚。第一步确认JBoss版本。不同版本查法不一样比较靠谱的是看安装目录下的文件老版本通常在${JBOSS_HOME}/version.txt或者bin/run.sh的参数里能看到EAP版本可以在modules/system/layers/base/org/jboss/as/product/eap/directory下找到版本信息。拿不准就登录管理控制台首页一般会直接显示版本号。第二步检查invoker映射是否开启。老版本JBoss的web容器默认部署文件里会声明一系列Servlet映射。以经典目录为例可以看server/default/deploy/jboss-web.deployer/conf/web.xml搜索关键字invoker、JMXInvokerServlet、EJBInvokerServlet。如果这些Servlet映射还在说明反序列化入口是开放的。第三步检查端口暴露情况。执行ss -tlnp | grep 8080看8080端口监听在什么地址上。如果监听的是0.0.0.0并且云平台安全组或防火墙对公网放行那这台机器就处于“公网可直连”的风险状态。第四步快速验证路径是否存在。在测试环境可以用curl -k -I http://目标IP:8080/invoker/JMXInvokerServlet如果返回状态是500、200或者包含异常堆栈信息说明这个入口可能还在处理请求。如果返回404说明Servlet映射大概率已经被移除。注意这只是验证入口存在性不要用生产环境做payload测试。3.2 首选方案升级或迁移处理优先级上我的建议是“能迁则迁不能迁就升级”。JBoss AS 4/5/6已经完全停止维护很多依赖组件库也老得没法修。网络和服务器层面的临时缓解只能拖时间根治只有一条路把业务迁到受支持的中间件上。如果业务短期没法迁至少要确保使用JBoss EAP系列并且升级到官方修复后的补丁版本。官方在2017年发布过针对CVE-2017-7504的安全公告EAP 6.x用户需要升级到包含修复的最新6.4.x补丁版。升级不是把二进制替换掉就完事。实操时要注意先把配置文件、部署包、线程池参数、类加载顺序全部记录下来在旁边的测试环境搭一套相同版本做回归再切生产。我见过不少“升级后应用起不来”的情况基本都是省略了测试这一步。3.3 快速缓解关掉不必要入口如果业务无法立刻升级至少要把风险入口关掉。老版本JBoss里找到上面提到的web.xml把HTTPInvoker相关的Servlet映射注释掉。示例!-- servlet-mapping servlet-nameJMXInvokerServlet/servlet-name url-pattern/invoker/JMXInvokerServlet/url-pattern /servlet-mapping --同理EJBInvokerServlet、restricted目录下的映射也应该一并处理。修改前先备份原文件并确认没有其他系统依赖这个接口。另一件重要的事是修改绑定地址避免监听公网地址。老版本启动时可以用sh run.sh -b 127.0.0.1EAP 6之后配置在standalone/configuration/standalone.xml里把public interface监听地址改成内网IP不要用0.0.0.0。3.4 给反序列化加“安检”JEP 290与自定义过滤器关掉Servlet入口是阻断但反序列化漏洞的狡猾之处在于你永远不知道业务系统里还有没有其他调用ObjectInputStream.readObject()的入口。所以还需要一层纵深防御在反序列化时加类型过滤器。如果你的JDK版本是8u121以上或者使用9及以上版本可以直接用JEP 290的ObjectInputFilterObjectInputFilter filter ObjectInputFilter.Config.createFilter( java.lang.*;java.util.*;javax.management.*;!* ); ObjectInputStream ois new ObjectInputStream(input); ois.setObjectInputFilter(filter);这个配置的意思是只允许反序列化java.lang、java.util、javax.management这几个包下的类其他一律拒绝。注意这里是白名单思路。白名单优于黑名单因为gadget chain的变体太多了靠黑名单永远堵不完。如果JDK版本太老跑不了JEP 290就需要通过实现自定义ObjectInputStream来覆盖resolveClass方法或者接入第三方反序列化过滤器组件。不过对老JDK来说最省事的方案其实是升级JDK毕竟一个2025年还在跑的操作环境不太应该继续停留在JDK 6/7上。有一点必须强调反序列化过滤器是“安全带”不是“方向盘”。它能防止部分绕过路径但不能替代“关闭入口升级版本”这两个核心动作。3.5 网络层兜底与WAF规则最后一道兜底在网络层把攻击流量挡在外面。层级手段重点拦截特征网络ACL防火墙/安全组只放行必要来源IP8080等管理端口不对公网开放WAF按路径过滤/invoker/相关请求WAF按内容特征过滤数据流中出现Java序列化魔数AC ED 00 05WAF按Content-Type过滤application/x-java-serialized-object如果是自建机房可以用iptables做端口级收敛比如只允许内网网段访问8080iptables -I INPUT -p tcp --dport 8080 -s 192.168.0.0/16 -j ACCEPT iptables -I INPUT -p tcp --dport 8080 -j DROP云环境就直接在安全组里配置来源IP白名单效果一样。配置完成后记得从公网侧验证一下端口是否已经不可达别改了规则却没人检查效果。4. 实际修复中踩过的坑与排查方法4.1 删了Servlet监控系统突然不采数了这是我踩过最实在的一个坑。当时删掉JMXInvokerServlet映射后业务侧看是正常了但过了几个小时监控平台开始大量报警“JMX数据采集失败”。排查后才发现某个监控采集模块一直在通过/invoker/JMXInvokerServlet远程读取JMX指标。删除前没有梳理依赖直接把监控搞停了。解决办法是先把调用关系摸清楚再决定怎么改。监控采集这类需求应该改成走JMX over Remoting或者用独立的监控Agent而不是依赖这个不安全的HTTP入口。经验就是删除风险接口前先问一句“谁在用”再动手。4.2 升级版本后应用直接起不来有一个项目升级EAP版本后应用启动时报各种ClassNotFoundException、NoSuchMethodError一排查都是老业务依赖了很旧的Commons Collections等第三方库新版本的类加载模块做了隔离直接冲突了。最终是通过调整模块依赖、显式声明依赖版本才解决。这类问题没有标准答案只能提醒升级前一定要在测试环境完整回归重点检查启动日志里的ClassNotFound、NoSuchMethodError以及JMX管理接口是否正常注册。4.3 只打补丁不关入口等于没修我曾见过一台标注“已升级”的JBoss访问/invoker/*路径仍然有响应。原因不复杂新版本虽然默认配置安全了但部署时管理员从旧目录复制了web.xml和一堆配置过来旧Servlet映射被原封不动带到了新环境。这提醒我安全整改的收尾必须做复验不是升级完就结束。收尾检查建议做成固定动作升级后再次访问关键路径确认返回404检查监听地址是否已收敛查看日志中是否还有对/invoker/的访问记录。这些动作看似简单却能拦住90%的“以为修好了”。4.4 WAF误拦正常Java客户端加WAF规则的时候如果全局拦截了“AC ED 00 05”这个特征很容易把正常业务也误伤。因为有些老旧Java客户端和服务器之间本来就在用Java原生序列化做RPC通信这些合法请求同样带着同样的魔数开头。我的建议是WAF规则尽量缩小范围精确到路径和来源。比如只拦截/invoker/路径下的序列化特征或者只拦截来自非可信来源IP的序列化请求。宁可规则稍微复杂一点也不要为省事而让正常业务躺枪。5. 别只补这一次后续的体系化防护5.1 把中间件资产台账建起来处理完这台JBoss之后我做的第一件事是把公司所有中间件资产整理成台账。没有台账安全巡检就是盲人摸象今天发现一台明天可能还有另一台。台账的核心字段可以参照这个结构资产IP端口中间件类型版本负责人是否公网暴露补丁状态最近检查时间10.10.1.58080JBoss EAP6.4.25某业务组否已修复2025-01-15最关键的一点是责任到人。每台服务器必须写明负责人没有负责人意味着没有应急响应能力。5.2 持续检测和变更管理有了台账之后还需要把检测动作变成周期任务。老JBoss这个级别的历史资产光靠一次巡检是不够的。我建议至少做到以下几条每月扫描一次中间件端口和/invoker/等历史风险路径新增部署时必须过安全Checklist不允许直接上停维版本的中间件任何变更都先走登记流程修改配置后必须复验安全策略对暂时无法迁移的业务登记风险并设定整改到期时间不能无限期挂账。这套动作做完再遇到类似CVE-2017-7504这样的公告时你手里已经有一份完整的资产清单能在几分钟内圈出受影响范围而不是从头开始翻服务器。5.3 代码层面把反序列化当成红线中间件加固只是治标应用代码里的反序列化使用习惯才是长期课题。在开发规范里我通常会把这几条写成强制红线不允许直接对不可信数据调用ObjectInputStream.readObject()如果必须接收序列化数据必须使用白名单过滤器或自定义安全ObjectInputStream尽量用JSON、Protocol Buffers等格式替代Java原生序列化第三方依赖库要定期升级及时跟踪漏洞公告。这些看起来是“软件工程规范”但实际是安全底线。很多JBoss反序列化最终能被利用就是因为整个调用链路上没有人考虑过“数据来源是否可信”。把这条红线刻进开发流程比事后一次次应急要划算得多。回头看这次整改我最大的体会是CVE-2017-7504本身不算新鲜但它背后的问题永远都不过时——技术债越久越贵。一台不知道谁负责的JBoss一个没人敢动的EAP版本一个开在公网上的8080组合起来就是一场可预见的灾难。如果你手里也有类似的系统越快找出它们、理清负责人、按上面的步骤逐步收紧后面省的不只是补漏洞的时间。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询