diff --git a/src/main/java/com/github/pfichtner/log4shell/scanner/Fingerprint.java b/src/main/java/com/github/pfichtner/log4shell/scanner/Fingerprint.java index db13c1c..ce6de3f 100644 --- a/src/main/java/com/github/pfichtner/log4shell/scanner/Fingerprint.java +++ b/src/main/java/com/github/pfichtner/log4shell/scanner/Fingerprint.java @@ -1,82 +1,82 @@ package com.github.pfichtner.log4shell.scanner; -import static java.util.Collections.emptySet; -import static java.util.Map.entry; import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; import static java.util.stream.Collectors.toUnmodifiableSet; +import static java.util.stream.IntStream.range; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.github.pfichtner.log4shell.scanner.DetectionCollector.Detection; import com.github.pfichtner.log4shell.scanner.detectors.AbstractDetector; -import com.github.pfichtner.log4shell.scanner.detectors.DirContextLookupsCallsFromJndiManager; -import com.github.pfichtner.log4shell.scanner.detectors.InitialContextLookupsCalls; -import com.github.pfichtner.log4shell.scanner.detectors.IsJndiEnabledPropertyAccess; -import com.github.pfichtner.log4shell.scanner.detectors.IsJndiEnabledPropertyAccessWithJdbcPrefix; -import com.github.pfichtner.log4shell.scanner.detectors.JndiLookupConstructorWithISException; -import com.github.pfichtner.log4shell.scanner.detectors.JndiManagerLookupCallsFromJndiLookup; -import com.github.pfichtner.log4shell.scanner.detectors.Log4jPluginAnnotation; -import com.github.pfichtner.log4shell.scanner.detectors.NamingContextLookupCallsFromJndiLookup; -import com.github.pfichtner.log4shell.scanner.detectors.NamingContextLookupCallsFromJndiManager; public class Fingerprint { - private static final Set> a = emptySet(); + private static final Charset utf8 = Charset.forName("UTF-8"); + private static final Pattern log4jPattern = Pattern.compile("log4j-core-(.+)\\.jar"); private static final Map>> mapping = mapping(); private static Map>> mapping() { - var b = Set.of(Log4jPluginAnnotation.class, InitialContextLookupsCalls.class); - var c = Set.of(NamingContextLookupCallsFromJndiLookup.class, Log4jPluginAnnotation.class); - var d = Set.of(JndiManagerLookupCallsFromJndiLookup.class, NamingContextLookupCallsFromJndiManager.class, - Log4jPluginAnnotation.class); - var e = Set.of(NamingContextLookupCallsFromJndiManager.class, Log4jPluginAnnotation.class, - IsJndiEnabledPropertyAccess.class); - var f = Set.of(JndiManagerLookupCallsFromJndiLookup.class, NamingContextLookupCallsFromJndiManager.class, - Log4jPluginAnnotation.class, IsJndiEnabledPropertyAccess.class, - JndiLookupConstructorWithISException.class); - var g = Set.of(JndiManagerLookupCallsFromJndiLookup.class, DirContextLookupsCallsFromJndiManager.class, - Log4jPluginAnnotation.class); - var h = Set.of(JndiManagerLookupCallsFromJndiLookup.class, DirContextLookupsCallsFromJndiManager.class, - Log4jPluginAnnotation.class, IsJndiEnabledPropertyAccess.class); - var i = Set.of(JndiManagerLookupCallsFromJndiLookup.class, Log4jPluginAnnotation.class, - InitialContextLookupsCalls.class, IsJndiEnabledPropertyAccess.class, - JndiLookupConstructorWithISException.class); - var j = Set.of(JndiManagerLookupCallsFromJndiLookup.class, Log4jPluginAnnotation.class, - InitialContextLookupsCalls.class, IsJndiEnabledPropertyAccess.class, - JndiLookupConstructorWithISException.class, IsJndiEnabledPropertyAccessWithJdbcPrefix.class); - - return Map.ofEntries( // - entry("2.0-alpha1", a), entry("2.0-alpha2", a), entry("2.0-beta1", a), entry("2.0-beta2", a), - entry("2.0-beta3", a), entry("2.0-beta4", a), entry("2.0-beta5", a), entry("2.0-beta6", a), - entry("2.0-beta7", a), entry("2.0-beta8", a), - // ************************************************************************************************ - entry("2.0-beta9", b), entry("2.0-rc1", b), - // ************************************************************************************************ - entry("2.0-rc2", c), entry("2.0", c), entry("2.0.1", c), entry("2.0.2", c), - // ************************************************************************************************ - entry("2.1", d), entry("2.2", d), entry("2.3", d), entry("2.4", d), entry("2.4.1", d), entry("2.5", d), - entry("2.6", d), entry("2.6.1", d), entry("2.6.2", d), entry("2.7", d), entry("2.8", d), - entry("2.8.1", d), entry("2.8.2", d), entry("2.9.0", d), entry("2.9.1", d), entry("2.10.0", d), - entry("2.11.0", d), entry("2.11.1", d), entry("2.11.2", d), entry("2.12.0", d), entry("2.12.1", d), - // ************************************************************************************************ - entry("2.12.2", e), - // ************************************************************************************************ - entry("2.12.3", f), - // ************************************************************************************************ - entry("2.13.0", d), entry("2.13.1", d), entry("2.13.2", d), entry("2.13.3", d), entry("2.14.0", d), - entry("2.14.1", d), - // ************************************************************************************************ - entry("2.15.0", g), - // ************************************************************************************************ - entry("2.16.0", h), - // ************************************************************************************************ - entry("2.17.0", i), - // ************************************************************************************************ - entry("2.17.1", j)); + Map>> map = new HashMap<>(); + Class[] classes = null; + for (String csvLine : readCsv()) { + String[] columns = csvLine.split("\\,"); + if (classes == null) { + classes = createClassesFromHeader(columns); + } else { + map.put(cutLog4Jcore(columns[0]), column(columns, classes)); + } + } + return map; + } + + private static Set> column(String[] columns, + Class[] detectors) { + return range(1, columns.length).filter(i -> "X".equals(columns[i])).mapToObj(i -> detectors[i]) + .collect(toSet()); + } + + @SuppressWarnings("unchecked") + private static Class[] createClassesFromHeader(String[] string) { + Class[] header = new Class[string.length]; + for (int i = 1; i < string.length; i++) { + header[i] = loadClass(string[i]); + } + return header; + } + + private static List readCsv() { + return new BufferedReader(new InputStreamReader(fingerprints(), utf8)).lines().collect(toList()); + } + + private static InputStream fingerprints() { + return Fingerprint.class.getResourceAsStream("fingerprints.csv"); + } + + private static String cutLog4Jcore(String name) { + Matcher matcher = log4jPattern.matcher(name); + return matcher.matches() ? matcher.group(1) : name; + } + + @SuppressWarnings("unchecked") + private static Class loadClass(String simpleClassName) { + try { + return (Class) Class + .forName(AbstractDetector.class.getPackageName() + "." + simpleClassName); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } } public static List getFingerprint(Collection detections) { diff --git a/src/main/resources/com/github/pfichtner/log4shell/scanner/fingerprints.csv b/src/main/resources/com/github/pfichtner/log4shell/scanner/fingerprints.csv new file mode 100644 index 0000000..03030d2 --- /dev/null +++ b/src/main/resources/com/github/pfichtner/log4shell/scanner/fingerprints.csv @@ -0,0 +1,50 @@ +File,JndiManagerLookupCallsFromJndiLookup,NamingContextLookupCallsFromJndiManager,NamingContextLookupCallsFromJndiLookup,DirContextLookupsCallsFromJndiManager,Log4jPluginAnnotation,InitialContextLookupsCalls,IsJndiEnabledPropertyAccess,JndiLookupConstructorWithISException,IsJndiEnabledPropertyAccessWithJdbcPrefix +log4j-core-2.0-alpha1.jar,,,,,,,,, +log4j-core-2.0-alpha2.jar,,,,,,,,, +log4j-core-2.0-beta1.jar,,,,,,,,, +log4j-core-2.0-beta2.jar,,,,,,,,, +log4j-core-2.0-beta3.jar,,,,,,,,, +log4j-core-2.0-beta4.jar,,,,,,,,, +log4j-core-2.0-beta5.jar,,,,,,,,, +log4j-core-2.0-beta6.jar,,,,,,,,, +log4j-core-2.0-beta7.jar,,,,,,,,, +log4j-core-2.0-beta8.jar,,,,,,,,, +log4j-core-2.0-beta9.jar,,,,,X,X,,, +log4j-core-2.0-rc1.jar,,,,,X,X,,, +log4j-core-2.0-rc2.jar,,,X,,X,,,, +log4j-core-2.0.jar,,,X,,X,,,, +log4j-core-2.0.1.jar,,,X,,X,,,, +log4j-core-2.0.2.jar,,,X,,X,,,, +log4j-core-2.1.jar,X,X,,,X,,,, +log4j-core-2.2.jar,X,X,,,X,,,, +log4j-core-2.3.jar,X,X,,,X,,,, +log4j-core-2.4.jar,X,X,,,X,,,, +log4j-core-2.4.1.jar,X,X,,,X,,,, +log4j-core-2.5.jar,X,X,,,X,,,, +log4j-core-2.6.jar,X,X,,,X,,,, +log4j-core-2.6.1.jar,X,X,,,X,,,, +log4j-core-2.6.2.jar,X,X,,,X,,,, +log4j-core-2.7.jar,X,X,,,X,,,, +log4j-core-2.8.jar,X,X,,,X,,,, +log4j-core-2.8.1.jar,X,X,,,X,,,, +log4j-core-2.8.2.jar,X,X,,,X,,,, +log4j-core-2.9.0.jar,X,X,,,X,,,, +log4j-core-2.9.1.jar,X,X,,,X,,,, +log4j-core-2.10.0.jar,X,X,,,X,,,, +log4j-core-2.11.0.jar,X,X,,,X,,,, +log4j-core-2.11.1.jar,X,X,,,X,,,, +log4j-core-2.11.2.jar,X,X,,,X,,,, +log4j-core-2.12.0.jar,X,X,,,X,,,, +log4j-core-2.12.1.jar,X,X,,,X,,,, +log4j-core-2.12.2.jar,,X,,,X,,X,, +log4j-core-2.12.3.jar,X,X,,,X,,X,X, +log4j-core-2.13.0.jar,X,X,,,X,,,, +log4j-core-2.13.1.jar,X,X,,,X,,,, +log4j-core-2.13.2.jar,X,X,,,X,,,, +log4j-core-2.13.3.jar,X,X,,,X,,,, +log4j-core-2.14.0.jar,X,X,,,X,,,, +log4j-core-2.14.1.jar,X,X,,,X,,,, +log4j-core-2.15.0.jar,X,,,X,X,,,, +log4j-core-2.16.0.jar,X,,,X,X,,X,, +log4j-core-2.17.0.jar,X,,,,X,X,X,X, +log4j-core-2.17.1.jar,X,,,,X,X,X,X,X