目录导读(Table of Contents)
- 引言:当“进攻”发生在Java代码里
- 第一步:看懂攻击面——案例中的“威胁信号”从哪来?
- 第二步:威胁程度评估的四个核心维度(CVSS + 业务影响)
- 第三步:实战拆解一个Java反序列化攻击案例
- 第四步:如何用代码特征快速判断“致命”与“骚扰”
- 常见问答(FAQ)——你纠结的威胁程度问题,答案在这
- 从“看案例”到“建防御”的思维跃迁
引言:当“进攻”发生在Java代码里
很多开发者和安全工程师在面对一个Java攻击案例(比如Log4Shell、Fastjson反序列化、Spring4Shell)时,第一反应是“这个漏洞严重吗?”,但“严重”是个模糊词——尤其当你手头只有一段攻击payload或一个堆栈日志时,你真正要回答的问题是:这波进攻对当前系统的威胁程度有多高?

答案不能靠感觉,而要靠一套可复用的评估框架,本文结合搜索引擎上已公开的数十个Java安全案例分析(包括OWASP Top 10、CVE详情库、GitHub安全公告),去伪存真,提炼出一套“从代码案例看威胁等级”的实操方法。
第一步:看懂攻击面——案例中的“威胁信号”从哪来?
任何Java攻击案例,首先要回答三个“W”:
- Who:攻击者是谁(外部匿名、已认证用户、内部低权限账号)?
- What:攻击入口是什么(HTTP接口、MQ消息、RMI、JNDI)?
- Where:缺陷代码部署在哪个层级(Controller、Service、三方库底层)?
典型威胁信号清单(高频出现在Java案例中):
| 信号特征 | 威胁含义 | 案例示例 |
|---|---|---|
ObjectInputStream.readObject() |
反序列化入口,极可能RCE | Fastjson @type 传入恶意类 |
jndi:ldap://... 出现在日志 |
JNDI注入,远程类加载 | Log4Shell(CVE-2021-44228) |
Runtime.exec() / ProcessBuilder |
命令执行,基本可判定为RCE | Spring表达式注入 |
Class.forName(用户可控值) |
动态类加载,可导致类路径污染 | Shiro反序列化 |
异常堆栈中出现org.springframework + |
SpEL注入,可执行任意表达式 | Spring4Shell(CVE-2022-22965) |
关键判断:如果攻击payload中出现了上述任何“危险类调用”,威胁级别至少是“高”,但还没完,你要结合攻击者的前置条件。
第二步:威胁程度评估的四个核心维度(CVSS + 业务影响)
单纯看漏洞本身(比如CVSS 9.8)是不够的,真正的威胁程度 = 漏洞可利用性 × 业务暴露面 × 数据敏感度 × 缓解措施有效性。
可利用性(Exploitability)
- 远程无认证触发 → 威胁 +2
- 需要登录但因未授权绕过可触发 → 威胁 +1
- 需要本地用户操作(如导入恶意文件) → 威胁 +0.5
业务暴露面(Exposure)
- 接口是否直接暴露在公网(Nginx/网关转发)?
- 是否存在于内网核心服务(如配置中心、认证服务)?
- 是否有WAF或RASP拦截了部分字段?
数据影响(Confidentiality/Integrity/Availability)
- 是否泄露令牌、密码、个人隐私(PII)?→ CIA都高
- 是否可篡改交易数据?→ I高
- 是否可导致Pod/进程崩溃?→ A高
缓解措施(Mitigation)
- 是否已打补丁?→ 已修补则威胁 -1
- 是否限制了出网策略(如禁LDAP协议)?→ 有效缓解降级
综合定级参考表(自制简单模型):
| 总分(0~10) | 威胁程度 | 建议响应 |
|---|---|---|
| 0~3 | 低(骚扰级) | 记录并观察 |
| 4~6 | 中(可被利用但限制多) | 优先级修复,临时禁用功能 |
| 7~9 | 高(可RCE且暴露面大) | 立即隔离,补丁/升级,强制告警 |
| 10 | 严重(全链路渗透) | 应急响应启动,业务停机 |
第三步:实战拆解一个Java反序列化攻击案例
假设你在日志中发现以下异常:
java.io.InvalidClassException: org.example.malicious.Exploit; local class incompatible
at java.io.ObjectStreamClass.checkCompatibility(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
攻击特征提取:
- 攻击者尝试向某个接口发送序列化对象(
readObject)。 - 类名
org.example.malicious.Exploit表明是自定义恶意类。 - 但报了
InvalidClassException,说明服务端JVM加载该类时反序列化校验失败——可能因为serialVersionUID不匹配,或安全过滤器拦截。
威胁程度评估(按前文框架):
| 维度 | 评估结果 | 得分 |
|---|---|---|
| 可利用性 | 攻击者已成功发送payload到反序列化入口,但未触发命令执行(因类校验失败) | +5 |
| 业务暴露面 | 该接口可能是用户注册或消息处理接口,直接暴露在公网 | +2 |
| 数据影响 | 若成功则RCE,可读文件、反弹Shell | +2 |
| 缓解措施 | 已有ObjectInputFilter限制类白名单,本次成功拦截 | -1 |
综合得分 = 5+2+2-1 = 8 → 高威胁但未实际危害。
这波进攻的“威胁程度”是高,因为你不能假设每次都能被InvalidClassException挡住,攻击者在持续尝试不同的恶意类名,一旦绕过过滤器就是灾难。
第四步:如何用代码特征快速判断“致命”与“骚扰”
如果你没有完整上下文,记住这几个“一眼定生死”的特征:
-
致命特征(威胁极高):
- payload中包含
ldap://、rmi://、dnslog.cn域名(回连验证)。 - 出现
base64.decode+ObjectInputStream组合,且decode内容包含javax.script.ScriptEngineManager。 - 调用栈中出现
tomcat.util.threads+ThreadPoolExecutor,且参数含 —— 表达式注入。
- payload中包含
-
骚扰特征(威胁较低但有风险):
- 只是扫描器探测(如
/..%2f、%27),没有实际的类加载。 - 有
ClassNotFound且类名是已知的公开PoC(比如com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter),但未继续执行。 - 日志中只出现一次,且来自同一IP的连续失败尝试。
- 只是扫描器探测(如
实操技巧:把攻击payload解码后,搜索其中是否包含java.lang.Runtime、ProcessBuilder、javax.naming.InitialContext,只要出现这三个类名之一,威胁级别直接定为“高”。
常见问答(FAQ)——你纠结的威胁程度问题,答案在这
Q1:CVE分数是10,但我当前系统没有用那个组件,威胁程度是0吗? 不是,CVE分数只描述漏洞本身,你的威胁 = CVE分数 × 你对该组件的暴露程度,如果组件存在但未启用受影响函数(如未使用JNDI),威胁可降为低;但如果组件是默认加载,则为高。
Q2:WAF拦截了攻击请求,威胁程度怎么算? WAF拦截降低了可利用性,建议威胁等级降一级,但要注意WAF规则是否覆盖所有变种(如大小写混淆、编码绕WAF),建议用实际变种测试。
Q3:案例中只看到攻击日志,没有回连,怎么判断是否成功? 未回连不代表失败,可能攻击者使用了外带数据(OOB)但被出网策略拦截,建议检查防火墙出站日志,看是否有到未知IP的443/53端口连接,若有,则威胁等级上调。
Q4:如何区分“安全研究员测试”和“真实攻击”? 看攻击频率和上下文:研究员通常只发一两个PoC载荷;真实攻击会持续更换payload、尝试多个漏洞点、且有后续持久化动作(如写webshell),建议结合SIEM关联规则。
从“看案例”到“建防御”的思维跃迁
“Java案例怎么看这波进攻的威胁程度?”——最终答案不是算出具体分数,而是建立一套可复用的威胁评估模型,你只需要记住四个字母:E-A-S-M(Exploitability, Exposure, Sensitivity, Mitigation),下次再看到一段陌生攻击日志,按这个顺序打分,你就能冷静地告诉团队:这是骚扰,还是紧急插拔网线。
真正的安全能力,不是记住所有CVE编号,而是能在5分钟内回答:这波进攻,值不值得我今晚不睡觉。 希望这篇文章能帮你少熬几个夜。
(注:文中所有域名示例均已脱敏,不指向任何真实攻击目标。)