
Una correzione basata su agente Java Byte Buddy per CVE-2021-44228, la vulnerabilità log4j 2.x "JNDI LDAP".
Un fix basato su un agente Java Byte Buddy per CVE-2021-44228, la vulnerabilità "JNDI LDAP" di log4j 2.x.
Fa tre cose:
jndi: ("lookups").System.err (cioè stderr) indicando che è stato effettuato un tentativo JNDI su log4j (inclusa la stringa di formato tentata, con eventuali caratteri ${} sanificati per prevenire iniezioni transitive)."(log4j jndi disabled)" nel messaggio di log (per prevenire iniezioni transitive).Aggiungi -javaagent:path/to/log4j-jndi-be-gone-1.0.0-standalone.jar ai tuoi comandi java.
Nota: Se hai già Byte Buddy nel classpath, prova a usare
log4j-jndi-be-gone-1.0.0.jar.
$ java -javaagent:path/to/log4j-jndi-be-gone-1.0.0-standalone.jar -jar path/to/some.jar
A partire dalla versione 1.1.0, log4j-jndi-be-gone tenta per impostazione predefinita di gestire le versioni ripacchettizzate (aka "shaded") di log4j che possono essere incorporate in un JAR sotto un nome di pacchetto alternativo per prevenire collisioni tra la versione di una dipendenza dell'applicazione e la versione della stessa dipendenza di un'altra dipendenza. Tuttavia, va notato che log4j non sembra essere facilmente ripacchettizzabile con nomi/prefix di pacchetto alternativi a causa dell'uso di riflessione con nomi di classe statici e/o nomi di classe da file di configurazione incorporati.
Questo comportamento può essere disabilitato inserendo =structureMatch=0 dopo il percorso del JAR dell'agente
nell'argomento -javaagent:, ad esempio:
-javaagent:path/to/log4j-jndi-be-gone-1.0.0-standalone.jar=structureMatch=0
che comporterà lo stesso comportamento di corrispondenza della versione 1.0.0, un semplice confronto esatto di stringhe rispetto al nome della classe.
Puoi creare il JAR con ./gradlew (build/libs/log4j-jndi-be-gone-1.0.0(-standalone).jar)
o prelevarlo dalla pagina delle release.
Il JAR dell'agente log4j-jndi-be-gone supporta Java 6-17+.
L'implementazione inizia cercando classi con suffissi che corrispondono ai
sotto-pacchetti più interni e al nome della classe di
org.apache.logging.log4j.core.lookup.JndiLookup,
lookup.JndiLookup, poiché ci si può ragionevolmente aspettare che
org.apache.logging.log4j.core sia stato modificato da regole di ripacchettizzamento che non cercavano di preservare i nomi dei pacchetti. Inoltre, invece di eseguire semplicemente controlli simili
per tutti gli altri tipi previsti di log4j, si assicura che esistano anche sotto lo stesso
pacchetto di base.
L'implementazione poi esamina la struttura di qualsiasi classe potenziale
lookup.JndiLookup di log4j identificata, tentando di convalidare rispetto a:
org.apache.logging.log4j.core.config.plugins.Plugin prevista
in tutte le versioni 2.x, inclusi i parametri dell'annotazione e i loro valorilookup(), verificando i suoi modificatori e la firma del tipo
(e ignorando la versione a 1 argomento della 2.0)convertJndiName(), verificando i suoi modificatori e la firma del tipoCONTAINER_JNDI_RESOURCE_PATH_PREFIX, verificando i suoi modificatorilog4j-jndi-be-gone non funzionerà se la libreria log4j è stata offuscata o se i suoi pacchetti/nomi di classe sono stati modificati in modo diverso da un semplice ri-pacchettizzamento (cioè "shading").
log4j-jndi-be-gone-1.0.0-standalone.jar include Byte Buddy al suo interno. Se
usi già Byte Buddy, potresti incontrare problemi. Prova
A partire dalla versione 1.1.0, il JAR standalone
di log4j-jndi-be-gone include una versione ripacchettizzata di Byte Buddy sotto il proprio prefisso di pacchetto.
Questo dovrebbe prevenire qualsiasi collisione.log4j-jndi-be-gone-1.0.0.jar invece, anche se nota che log4j-jndi-be-gone
si aspetta Byte Buddy 1.12.x.
Se hai sostituito le tue classi JndiLookup con implementazioni che
tentano di fare honeypotting o registrare chiamate lookup(), log4j-jndi-be-gone
potrebbe potenzialmente disabilitare il loro metodo lookup, impedendone il funzionamento.
La directory tests/jnditest contiene un semplice caso di test in cui una chiamata di log
di log4j passa una stringa di formato JNDI LDAP. Imposta anche un proprio
listener di porta per determinare se log4j ha effettuato un tentativo di connessione e
fa fallire il test se è stata ricevuta una connessione.
$ ./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)
Concesso in licenza secondo la licenza Apache 2.
log4j-jndi-be-gone è stato testato su OpenJDK 6, 8, 11 e 17, e sulle JVM HotSpot e OpenJ9.