@@ -37,11 +37,14 @@ public class Detector {
37
37
private static final String LOG4J_12_CORE_POM_PROPS = "META-INF/maven/log4j/log4j/pom.properties" ;
38
38
private static final String LOG4J_12_JMSAPPENDER = "org/apache/log4j/net/JMSAppender.class" ;
39
39
private static final String LOG4J_12_JMSAPPENDER_SHADE_PATH = "/log4j/net/JMSAppender.class" ;
40
+ private static final String LOG4J_12_JMSSINK = "org/apache/log4j/net/JMSSink.class" ;
41
+ private static final String LOG4J_12_JMSSINK_SHADE_PATH = "/log4j/net/JMSSink.class" ;
40
42
41
43
// CVE-2021-42550 (published at 2021-12-16): vulnerable if version <= 1.2.7
42
44
// logback 1.2.9 moved JNDIUtil.class to core package
43
45
private static final String LOGBACK_CLASSIC_POM_PROPS = "META-INF/maven/ch.qos.logback/logback-classic/pom.properties" ;
44
46
private static final String LOGBACK_JNDI_CLASS_PATH = "ch/qos/logback/classic/util/JNDIUtil.class" ;
47
+ private static final String LOGBACK_ENV_CLASS_PATH = "ch/qos/logback/classic/util/EnvUtil.class" ;
45
48
46
49
private Configuration config ;
47
50
@@ -202,9 +205,11 @@ private DetectResult scanStream(File jarFile, ZipFileIterator it, List<String> p
202
205
203
206
// log4j1 class
204
207
boolean foundJmsAppender = false ;
208
+ boolean foundJmsSink = false ;
205
209
206
210
// logback class
207
211
boolean foundJndiUtil = false ;
212
+ boolean foundEnvUtil = false ;
208
213
209
214
// shade class
210
215
Set <String > shadedJndiLookupPaths = new TreeSet <String >();
@@ -218,7 +223,7 @@ private DetectResult scanStream(File jarFile, ZipFileIterator it, List<String> p
218
223
219
224
InputStream is = it .getNextInputStream ();
220
225
if (entry .getName ().equals (LOG4J_CORE_POM_PROPS ))
221
- log4j2Version = loadVulnerableLog4jVersion (is );
226
+ log4j2Version = loadLog4j2Version (is );
222
227
223
228
if (entry .getName ().equals (JNDI_LOOKUP_CLASS_PATH ))
224
229
log4j2Mitigated = false ;
@@ -228,21 +233,30 @@ private DetectResult scanStream(File jarFile, ZipFileIterator it, List<String> p
228
233
229
234
if (config .isScanForLog4j1 ()) {
230
235
if (entry .getName ().equals (LOG4J_12_CORE_POM_PROPS ))
231
- log4j1Version = loadVulnerableLog4j1 (is );
236
+ log4j1Version = loadLog4j1Version (is );
232
237
233
238
if (entry .getName ().equals (LOG4J_12_JMSAPPENDER ))
234
239
foundJmsAppender = true ;
235
240
241
+ if (entry .getName ().equals (LOG4J_12_JMSSINK ))
242
+ foundJmsSink = true ;
243
+
236
244
if (entry .getName ().endsWith (LOG4J_12_JMSAPPENDER_SHADE_PATH ))
237
245
shadedJmsAppenderPaths .add (entry .getName ());
246
+
247
+ if (entry .getName ().endsWith (LOG4J_12_JMSSINK_SHADE_PATH ))
248
+ foundJmsSink = true ;
238
249
}
239
250
240
251
if (config .isScanForLogback ()) {
241
252
if (entry .getName ().equals (LOGBACK_CLASSIC_POM_PROPS ))
242
- logbackVersion = loadVulnerableLogback (is );
253
+ logbackVersion = loadLogbackVersion (is );
243
254
244
255
if (entry .getName ().equals (LOGBACK_JNDI_CLASS_PATH ))
245
256
foundJndiUtil = true ;
257
+
258
+ if (entry .getName ().equals (LOGBACK_ENV_CLASS_PATH ))
259
+ foundEnvUtil = true ;
246
260
}
247
261
248
262
if (ZipUtils .isScanTarget (entry .getName (), config .isScanZip ())) {
@@ -275,26 +289,36 @@ private DetectResult scanStream(File jarFile, ZipFileIterator it, List<String> p
275
289
result .setPotentiallyVulnerableLog4j2 ();
276
290
}
277
291
278
- if (log4j1Version != null ) {
279
- printDetectionForLog4j1 (jarFile , pathChain , log4j1Version , !foundJmsAppender );
280
- if (foundJmsAppender )
281
- result .setPotentiallyVulnerableLog4j1 ();
292
+ boolean log4j1Found = log4j1Version != null || foundJmsAppender || foundJmsSink ;
293
+ boolean log4j1Mitigated = !foundJmsAppender ;
294
+ log4j1Mitigated &= shadedJmsAppenderPaths .isEmpty ();
295
+
296
+ if (log4j1Found ) {
297
+ if (log4j1Version != null )
298
+ printDetectionForLog4j1 (jarFile , pathChain , log4j1Version , log4j1Mitigated );
282
299
else
300
+ printDetectionForLog4j1 (jarFile , pathChain , POTENTIALLY_VULNERABLE , log4j1Mitigated );
301
+
302
+ if (log4j1Mitigated )
283
303
result .setMitigated ();
284
- } else if (foundJmsAppender ) {
285
- printDetectionForLog4j1 (jarFile , pathChain , POTENTIALLY_VULNERABLE , false );
286
- result .setPotentiallyVulnerableLog4j1 ();
304
+ else
305
+ result .setPotentiallyVulnerableLog4j1 ();
287
306
}
288
307
289
- if (logbackVersion != null ) {
290
- printDetectionForLogback (jarFile , pathChain , logbackVersion , !foundJndiUtil );
291
- if (foundJndiUtil )
292
- result .setPotentiallyVulnerableLogback ();
293
- else
308
+ boolean logbackFound = isVulnerableLogback (logbackVersion , foundJndiUtil , foundEnvUtil );
309
+ boolean logbackMitigated = !foundJndiUtil ;
310
+
311
+ if (logbackFound ) {
312
+ if (logbackVersion != null ) {
313
+ printDetectionForLogback (jarFile , pathChain , logbackVersion , logbackMitigated );
314
+ } else {
315
+ printDetectionForLogback (jarFile , pathChain , POTENTIALLY_VULNERABLE , logbackMitigated );
316
+ }
317
+
318
+ if (logbackMitigated )
294
319
result .setMitigated ();
295
- } else if (foundJndiUtil ) {
296
- printDetectionForLogback (jarFile , pathChain , POTENTIALLY_VULNERABLE , false );
297
- result .setPotentiallyVulnerableLogback ();
320
+ else
321
+ result .setPotentiallyVulnerableLogback ();
298
322
}
299
323
300
324
return result ;
@@ -307,6 +331,17 @@ private DetectResult scanStream(File jarFile, ZipFileIterator it, List<String> p
307
331
}
308
332
}
309
333
334
+ private boolean isVulnerableLogback (String logbackVersion , boolean foundJndiUtil , boolean foundEnvUtil ) {
335
+ boolean logbackFound = false ;
336
+ if (logbackVersion != null ) {
337
+ if (isVulnerableLogback (Version .parse (logbackVersion )))
338
+ logbackFound = true ;
339
+ } else {
340
+ logbackFound = foundJndiUtil || foundEnvUtil ;
341
+ }
342
+ return logbackFound ;
343
+ }
344
+
310
345
private boolean isWinRarFile (File jarFile , List <String > pathChain ) {
311
346
String fileName = null ;
312
347
if (pathChain .isEmpty ())
@@ -317,7 +352,7 @@ private boolean isWinRarFile(File jarFile, List<String> pathChain) {
317
352
return fileName .toLowerCase ().endsWith (".rar" );
318
353
}
319
354
320
- private String loadVulnerableLog4jVersion (InputStream is ) throws IOException {
355
+ private String loadLog4j2Version (InputStream is ) throws IOException {
321
356
Properties props = new Properties ();
322
357
props .load (is );
323
358
@@ -331,26 +366,22 @@ private String loadVulnerableLog4jVersion(InputStream is) throws IOException {
331
366
return null ;
332
367
}
333
368
334
- private String loadVulnerableLog4j1 (InputStream is ) throws IOException {
369
+ private String loadLog4j1Version (InputStream is ) throws IOException {
335
370
Properties props = new Properties ();
336
371
props .load (is );
337
-
338
372
return props .getProperty ("version" );
339
373
}
340
374
341
- private String loadVulnerableLogback (InputStream is ) throws IOException {
375
+ private String loadLogbackVersion (InputStream is ) throws IOException {
342
376
Properties props = new Properties ();
343
377
props .load (is );
344
378
345
379
String groupId = props .getProperty ("groupId" );
346
380
String artifactId = props .getProperty ("artifactId" );
347
381
String version = props .getProperty ("version" );
348
382
349
- if (groupId .equals ("ch.qos.logback" ) && artifactId .equals ("logback-classic" )) {
350
- Version v = Version .parse (version );
351
- if (isVulnerableLogback (v ))
352
- return version ;
353
- }
383
+ if (groupId .equals ("ch.qos.logback" ) && artifactId .equals ("logback-classic" ))
384
+ return version ;
354
385
355
386
return null ;
356
387
}
0 commit comments