Log4j 漏洞原理
1. Log4j 的“查找”(Lookups)功能
Log4j 是一个强大的日志框架,它有一个非常实用的功能叫做 “查找”(Lookups)。这个功能允许在日志配置或日志消息中动态地获取一些信息
比如,你可以用 ${sys:user.name}
来打印当前系统的用户名,或者用 ${env:PATH}
来打印系统的环境变量
这些 Lookups 机制让日志功能变得非常灵活
2. JNDI 查找的引入
在 Log4j 的 2.x 版本中,引入了一种新的查找类型:JNDI Lookup
- JNDI(Java Naming and Directory Interface)是 Java 平台的一个 API,它允许程序通过名字来查找和访问各种资源,比如数据库、远程对象等
- JNDI 查找支持多种协议,例如:
LDAP
(轻量级目录访问协议)、RMI
(远程方法调用) 和DNS
等
有了 JNDI Lookup,你就可以在日志消息中通过 ${jndi:协议://地址}
的形式去查询一个远程资源
3. 漏洞的核心:JNDI 远程加载类
漏洞的真正核心在于 JNDI 协议的特性
当 Log4j 看到一个 ${jndi:ldap://...}
字符串时,它会:
- 解析:识别这是一个 JNDI 查找
- 请求:向
ldap://
指定的远程服务器发起请求 - 接收响应:LDAP 服务器会返回一个恶意的 Java 对象(或者说,指向这个对象的引用)。这个对象通常是一个恶意的
.class
文件 - 远程加载:客户端(即 Log4j 所在的程序)在处理这个返回的对象时,会自动去加载并实例化这个恶意的
.class
文件
这个过程,就是 JNDI 注入。它利用了 JNDI 协议的特性,让程序主动去加载并执行远程服务器上的代码