
Ein auf Byte Buddy basierender Java-Agent-Fix für CVE-2021-44228, die „JNDI LDAP“-Sicherheitslücke in log4j 2.x.
Eine auf Byte Buddy basierende Java-Agent-Lösung für CVE-2021-44228, die log4j-2.x-"JNDI-LDAP"-Schwachstelle.
Sie tut drei Dinge:
jndi:-Formatstrings ("Lookups").System.err (d. h. stderr), die anzeigt, dass ein log4j-JNDI-
Versuch unternommen wurde (einschließlich des versuchten Formatstrings, wobei alle ${}-
Zeichen bereinigt werden, um transitive Injection zu verhindern)."(log4j jndi disabled)" auf
(um transitive Injection zu verhindern).Fügen Sie -javaagent:path/to/log4j-jndi-be-gone-1.0.0-standalone.jar zu Ihren java-Befehlen hinzu.
Hinweis: Wenn Sie bereits Byte Buddy im Klassenpfad haben, versuchen Sie,
log4j-jndi-be-gone-1.0.0.jar zu verwenden.
$ java -javaagent:path/to/log4j-jndi-be-gone-1.0.0-standalone.jar -jar path/to/some.jar
Ab Version 1.1.0 versucht log4j-jndi-be-gone standardmäßig, umverpackte (auch "shaded" genannte) Versionen von log4j zu behandeln, die in einer JAR unter einem alternativen Paketnamen eingebettet sein können, um Kollisionen zwischen der Version einer Abhängigkeit in einer Anwendung und der Version derselben Abhängigkeit in einer anderen Abhängigkeit zu vermeiden. Es sollte jedoch beachtet werden, dass log4j offenbar nicht ohne Weiteres unter alternativen Paketnamen/-präfixen umverpackt werden kann, da Reflection mit statischen Klassennamen und/oder Klassennamen aus eingebetteten Konfigurationsdateien verwendet wird.
Dieses Verhalten kann deaktiviert werden, indem =structureMatch=0 nach dem Agent-JAR-Pfad
im -javaagent:-Argument platziert wird, z. B.:
-javaagent:path/to/log4j-jndi-be-gone-1.0.0-standalone.jar=structureMatch=0
Dies führt zu demselben Abgleichverhalten wie in 1.0.0, einem einfachen exakten String- Vergleich gegen den Klassennamen.
Sie können die JAR mit ./gradlew (build/libs/log4j-jndi-be-gone-1.0.0(-standalone).jar) erstellen
oder sie von der Releases-Seite herunterladen.
Die log4j-jndi-be-gone-Agent-JAR unterstützt Java 6-17+.
Die Implementierung beginnt mit dem Abgleich von Klassen, deren Suffixe mit den
innersten Unterpaketen und dem Klassennamen von
org.apache.logging.log4j.core.lookup.JndiLookup,
lookup.JndiLookup übereinstimmen, da vernünftigerweise erwartet werden kann, dass
org.apache.logging.log4j.core durch Umverpackungsregeln verändert wurde, die nicht darauf
abzielten, Paketnamen zu erhalten. Zusätzlich wird nicht nur eine ähnliche Prüfung für alle
anderen erwarteten log4j-Typen durchgeführt, sondern auch sichergestellt, dass sie unter
demselben Basispaket existieren.
Die Implementierung durchläuft dann die Struktur aller identifizierten potenziellen
log4j-lookup.JndiLookup-Klassen und versucht, diese zu validieren anhand von:
org.apache.logging.log4j.core.config.plugins.Plugin-Annotation, die in allen
2.x-Versionen erwartet wird, einschließlich der Annotationsparameter und ihrer Wertelookup(), abgeglichen gegen ihre Modifikatoren und Typsignatur
(wobei die 1-Argument-Variante aus 2.0 ignoriert wird)convertJndiName(), abgeglichen gegen ihre Modifikatoren und TypsignaturCONTAINER_JNDI_RESOURCE_PATH_PREFIX, abgeglichen gegen seine Modifikatorenlog4j-jndi-be-gone funktioniert nicht, wenn die log4j-Bibliothek verschleiert (obfuscated) wurde oder wenn ihre Klassenpakete/-namen außer durch grundlegendes Umverpacken (d. h. "Shading") verändert wurden.
log4j-jndi-be-gone-1.0.0-standalone.jar bündelt Byte Buddy. Wenn Sie
bereits Byte Buddy verwenden, könnten Probleme damit auftreten. Verwenden Sie
stattdessen Ab Version 1.1.0 bündelt das log4j-jndi-be-gone-Standalone-JAR
ein umverpacktes Byte Buddy unter einem eigenen Paketpräfix.
Dies sollte jegliche Kollisionen verhindern.log4j-jndi-be-gone-1.0.0.jar, beachten Sie jedoch, dass log4j-jndi-be-gone
Byte Buddy 1.12.x erwartet.
Wenn Sie Ihre JndiLookup-Klassen durch Implementierungen ersetzt haben, die
Honeypotting betreiben oder lookup()-Aufrufe protokollieren, wird log4j-jndi-be-gone
möglicherweise deren lookup-Methode deaktivieren und sie so an der Arbeit hindern.
Das Verzeichnis tests/jnditest enthält einen einfachen Testfall, bei dem ein log4j-Logging-
Aufruf einen JNDI-LDAP-Formatstring übergibt. Es richtet außerdem einen eigenen Port-
Listener ein, um festzustellen, ob log4j einen Verbindungsversuch unternommen hat, und lässt
den Test fehlschlagen, wenn eine Verbindung empfangen wurde.
$ ./tests/jnditest/test-uninstrumented.sh
BUILD SUCCESSFUL in 1s
6 actionable tasks: 5 executed, 1 up-to-date
BUILD SUCCESSFUL in 1s
3 actionable tasks: 3 up-to-date
JUnit version 4.12
.16:08:49.547 [main] ERROR trust.nccgroup.jnditest.test.JndiTest - Hello, _${jndi:ldap://127.0.0.1:8899/evil}_!
E
Time: 0.929
There was 1 failure:
1) logging(trust.nccgroup.jnditest.test.JndiTest)
java.lang.AssertionError: jndi ldap connection received
at org.junit.Assert.fail(Assert.java:88)
at trust.nccgroup.jnditest.test.JndiTest.logging(JndiTest.java:55)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.runner.JUnitCore.runMain(JUnitCore.java:77)
at org.junit.runner.JUnitCore.main(JUnitCore.java:36)
at trust.nccgroup.jnditest.Main.main(Main.java:24)
FAILURES!!!
Tests run: 1, Failures: 1
$ ./tests/jnditest/test-instrumented.sh
BUILD SUCCESSFUL in 1s
6 actionable tasks: 5 executed, 1 up-to-date
BUILD SUCCESSFUL in 1s
3 actionable tasks: 3 up-to-date
JUnit version 4.12
.log4j jndi lookup attempted: (sanitized) ldap://127.0.0.1:8899/evil
16:09:06.064 [main] ERROR trust.nccgroup.jnditest.test.JndiTest - Hello, _(log4j jndi disabled)_!
Time: 1.362
OK (1 test)
Lizenziert unter der Apache-2-Lizenz.
log4j-jndi-be-gone wurde auf OpenJDK 6, 8, 11 und 17 sowie auf den JVMs HotSpot und OpenJ9 getestet.