@@ -49,6 +49,8 @@ public class Log4JDetector {
4949 private static final String FILE_LOG4J_2_10 = "appender/nosql/NoSqlAppender." .toLowerCase (Locale .ROOT );
5050 private static final String FILE_LOG4J_JNDI_LOOKUP = "core/lookup/JndiLookup." .toLowerCase (Locale .ROOT );
5151 private static final String FILE_LOG4J_JNDI_MANAGER = "core/net/JndiManager." .toLowerCase (Locale .ROOT );
52+ private static final String FILE_LOG4J_JDBC_DSCS = "core/appender/db/jdbc/DataSourceConnectionSource." .toLowerCase (Locale .ROOT );
53+
5254 private static final String FILE_GONE_LOG4J_2_17 = "core/util/SetUtils." .toLowerCase (Locale .ROOT );
5355
5456 private static final String ACTUAL_FILE_LOG4J_2 = "core/Appender.class" ;
@@ -59,6 +61,7 @@ public class Log4JDetector {
5961 private static final String ACTUAL_FILE_GONE_LOG4J_2_17 = "core/util/SetUtils.class" ;
6062 private static final String ACTUAL_FILE_LOG4J_JNDI_LOOKUP = "core/lookup/JndiLookup.class" ;
6163 private static final String ACTUAL_FILE_LOG4J_JNDI_MANAGER = "core/net/JndiManager.class" ;
64+ private static final String ACTUAL_FILE_LOG4J_JDBC_DSCS = "core/appender/db/jdbc/DataSourceConnectionSource.class" ;
6265
6366 // This occurs in "JndiManager.class" in 2.15.0
6467 private static final byte [] IS_LOG4J_SAFE_2_15_0 = Bytes .fromString ("Invalid JNDI URI - {}" );
@@ -75,6 +78,9 @@ public class Log4JDetector {
7578 // This occurs in "JndiManager.class" in 2.3.1
7679 private static final byte [] IS_LOG4J_SAFE_2_3_1 = Bytes .fromString ("Unsupported JNDI URI - {}" );
7780
81+ // This occurs in "DataSourceConnectionSource.class" in 2.17.1 and friends.
82+ private static final byte [] IS_CVE_2021_44832_SAFE = Bytes .fromString ("JNDI must be enabled by setting log4j2.enableJndiJdbc=true" );
83+
7884 private static boolean verbose = false ;
7985 private static boolean debug = false ;
8086 private static boolean json = false ;
@@ -131,7 +137,7 @@ public static void main(String[] args) throws IOException {
131137
132138 if (argsList .isEmpty ()) {
133139 System .out .println ();
134- System .out .println ("Usage: java -jar log4j-detector-2021.12.22 .jar [--verbose] [--json] [--stdin] [--exclude=X] [paths to scan...]" );
140+ System .out .println ("Usage: java -jar log4j-detector-2021.12.29 .jar [--verbose] [--json] [--stdin] [--exclude=X] [paths to scan...]" );
135141 System .out .println ();
136142 System .out .println (" --json - Output STDOUT results in JSON. (Errors/warning still emitted to STDERR)" );
137143 System .out .println (" --stdin - Parse STDIN for paths to explore." );
@@ -143,14 +149,14 @@ public static void main(String[] args) throws IOException {
143149 System .out .println (" 1 = At least one legacy Log4J 1.x version found." );
144150 System .out .println (" 2 = At least one vulnerable Log4J 2.x version found." );
145151 System .out .println ();
146- System .out .println ("About - MergeBase log4j detector (version 2021.12.22 )" );
152+ System .out .println ("About - MergeBase log4j detector (version 2021.12.29 )" );
147153 System .out .println ("Docs - https://github.com/mergebase/log4j-detector " );
148154 System .out .println ("(C) Copyright 2021 Mergebase Software Inc. Licensed to you via GPLv3." );
149155 System .out .println ();
150156 System .exit (100 );
151157 }
152158
153- System .err .println ("-- github.com/mergebase/log4j-detector v2021.12.22 (by mergebase.com) analyzing paths (could take a while)." );
159+ System .err .println ("-- github.com/mergebase/log4j-detector v2021.12.29 (by mergebase.com) analyzing paths (could take a while)." );
154160 System .err .println ("-- Note: specify the '--verbose' flag to have every file examined printed to STDERR." );
155161 if (json ) {
156162 System .out .println ("{\" hits\" :[" );
@@ -186,11 +192,12 @@ private static int nextByte(int[] four, InputStream in) throws IOException {
186192 four [1 ] = four [2 ];
187193 four [2 ] = four [3 ];
188194 four [3 ] = in .read ();
195+ File f = new File ("blah" );
189196 return four [3 ];
190197 }
191198
192- private static boolean isZipSentinel (int [] four ) {
193- return four [0 ] == 0x50 && four [1 ] == 0x4B && four [2 ] == 3 && four [3 ] == 4 ;
199+ private static boolean isZipSentinel (int [] chunk ) {
200+ return chunk [0 ] == 0x50 && chunk [1 ] == 0x4B && chunk [2 ] == 3 && chunk [3 ] == 4 ;
194201 }
195202
196203 private static final Comparator <File > FILES_ORDER_BY_NAME = new Comparator <File >() {
@@ -227,12 +234,9 @@ private static int fileType(String fileName) {
227234 } else if ("class" .equalsIgnoreCase (suffix )) {
228235 return 1 ;
229236 } else if ("zip" .equalsIgnoreCase (suffix )
230- || "jar" .equalsIgnoreCase (suffix )
231237 || "jpi" .equalsIgnoreCase (suffix )
232238 || "hpi" .equalsIgnoreCase (suffix )
233- || "war" .equalsIgnoreCase (suffix )
234- || "ear" .equalsIgnoreCase (suffix )
235- || "aar" .equalsIgnoreCase (suffix )) {
239+ || suffix .endsWith ("ar" )) {
236240 return 0 ;
237241 }
238242 }
@@ -273,6 +277,7 @@ private static void findLog4jRecursive(
273277 boolean isLog4j2_10 = false ;
274278 boolean hasJndiLookup = false ;
275279 boolean hasJndiManager = false ;
280+ boolean hasJdbcJndiDisabled = false ;
276281 boolean hasSetUtils = false ;
277282 boolean isLog4J1_X = false ;
278283 boolean isLog4j2_15 = false ;
@@ -316,12 +321,9 @@ private static void findLog4jRecursive(
316321 boolean needClassBytes = false ;
317322 final boolean isJndiLookup = pathLower .contains (FILE_LOG4J_JNDI_LOOKUP );
318323 final boolean isJndiManager = pathLower .contains (FILE_LOG4J_JNDI_MANAGER );
324+ final boolean isJdbcConnManager = pathLower .contains (FILE_LOG4J_JDBC_DSCS );
319325
320- if (isPomProperties ) {
321- needClassBytes = true ;
322- } else if (isJndiLookup ) {
323- needClassBytes = true ;
324- } else if (isJndiManager ) {
326+ if (isPomProperties || isJndiLookup || isJndiManager || isJdbcConnManager ) {
325327 needClassBytes = true ;
326328 }
327329
@@ -380,6 +382,10 @@ public void close() {
380382 if (pathLower .endsWith (POM_PROPERTIES )) {
381383 pomProperties = bytes ;
382384 pomPath = "!/" + path ;
385+ } else if (isJdbcConnManager ) {
386+ if (containsMatch (bytes , IS_CVE_2021_44832_SAFE )) {
387+ hasJdbcJndiDisabled = true ;
388+ }
383389 } else if (pathLower .contains (FILE_OLD_LOG4J )) {
384390 isLog4J1_X = true ;
385391 } else if (pathLower .contains (FILE_LOG4J_1 )) {
@@ -414,9 +420,9 @@ public void close() {
414420 }
415421 } else {
416422 isLog4j2_15_override = true ;
417- if ( containsMatch ( bytes , IS_LOG4J_SAFE_2_3_1 )) {
418- isLog4j2_3_1 = true ;
419- }
423+ }
424+ if ( containsMatch ( bytes , IS_LOG4J_SAFE_2_3_1 )) {
425+ isLog4j2_3_1 = true ;
420426 }
421427 }
422428 }
@@ -499,9 +505,17 @@ public void close() {
499505 foundHits = true ;
500506 } else {
501507 if (isLog4j2_12_3 ) {
502- buf .append ("== 2.12.3 _SAFE_" );
508+ if (hasJdbcJndiDisabled ) {
509+ buf .append ("== 2.12.4 _SAFE_" );
510+ } else {
511+ buf .append ("== 2.12.3 _OKAY_" );
512+ }
503513 } else if (isLog4j2_17 ) {
504- buf .append (">= 2.17.0 _SAFE_" );
514+ if (hasJdbcJndiDisabled ) {
515+ buf .append (">= 2.17.1 _SAFE_" );
516+ } else {
517+ buf .append ("== 2.17.0 _OKAY_" );
518+ }
505519 } else if (isLog4j2_16 ) {
506520 buf .append ("== 2.16.0 _OKAY_" );
507521 foundHits = true ;
@@ -516,7 +530,11 @@ public void close() {
516530 } else {
517531 if (isLog4j2_3_1 ) {
518532 isSafe = true ;
519- buf .append ("== 2.3.1 _SAFE_" );
533+ if (hasJdbcJndiDisabled ) {
534+ buf .append ("== 2.3.2 _SAFE_" );
535+ } else {
536+ buf .append ("== 2.3.1 _OKAY_" );
537+ }
520538 } else {
521539 buf .append (">= 2.0-beta9 (< 2.10.0) _VULNERABLE_" );
522540 }
@@ -750,6 +768,15 @@ private static void analyze(File f) {
750768 jndiManagerBytes = Bytes .fileToBytes (jndiManager );
751769 }
752770
771+ boolean hasJdbcJndiDisabled = false ;
772+ File jdbcConn = new File (f .getParent () + "/../" + ACTUAL_FILE_LOG4J_JDBC_DSCS );
773+ if (jdbcConn .canRead ()) {
774+ byte [] jdbcConnBytes = Bytes .fileToBytes (jdbcConn );
775+ if (containsMatch (jdbcConnBytes , IS_CVE_2021_44832_SAFE )) {
776+ hasJdbcJndiDisabled = true ;
777+ }
778+ }
779+
753780 boolean hasSetUtils = exists (f .getParent () + "/../" + ACTUAL_FILE_GONE_LOG4J_2_17 );
754781 if (exists (f .getParent () + "/../" + ACTUAL_FILE_LOG4J_2 )) {
755782 if (exists (f .getParent () + "/../" + ACTUAL_FILE_LOG4J_3 )) {
@@ -808,9 +835,17 @@ private static void analyze(File f) {
808835 if (isLog4J_2_10 ) {
809836 if (isLog4J_2_17 ) {
810837 if (hasSetUtils ) {
811- buf .append (">= 2.12.3 _SAFE_" );
838+ if (hasJdbcJndiDisabled ) {
839+ buf .append ("== 2.12.4 _SAFE_" );
840+ } else {
841+ buf .append ("== 2.12.3 _OKAY_" );
842+ }
812843 } else {
813- buf .append (">= 2.17.0 _SAFE_" );
844+ if (hasJdbcJndiDisabled ) {
845+ buf .append (">= 2.17.1 _SAFE_" );
846+ } else {
847+ buf .append ("== 2.17.0 _OKAY_" );
848+ }
814849 }
815850 } else if (isLog4J_2_15 ) {
816851 foundHits = true ;
@@ -829,7 +864,11 @@ private static void analyze(File f) {
829864 }
830865 } else {
831866 if (isLog4J_2_3_1 ) {
832- buf .append ("== 2.3.1 _SAFE_" );
867+ if (hasJdbcJndiDisabled ) {
868+ buf .append ("== 2.3.2 _SAFE_" );
869+ } else {
870+ buf .append ("== 2.3.1 _OKAY_" );
871+ }
833872 } else {
834873 buf .append (">= 2.0-beta9 (< 2.10.0) _VULNERABLE_" );
835874 foundHits = true ;
0 commit comments