Skip to content

Commit 22c7ca7

Browse files
committed
v2021.12.20 - some new options (--json, --stdin, --excludes)
includes pre-compiled ./log4j-detector-2021.12.20.jar binary that was compiled using Java 6 and signed by MergeBase signing key.
1 parent f8883b4 commit 22c7ca7

File tree

4 files changed

+97
-23
lines changed

4 files changed

+97
-23
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ We currently maintain a collection of [log4j-samples](https://github.com/mergeba
1313

1414
# Example Usage:
1515

16-
java -jar log4j-detector-2021.12.17.jar [path-to-scan] > hits.txt
16+
java -jar log4j-detector-2021.12.20.jar [path-to-scan] > hits.txt
1717

1818
![Terminal output from running java -jar log4j-detector.jar in a terminal](./log4j-detector.png)
1919

2020
# More Example Usage:
2121

2222
```
23-
java -jar log4j-detector-2021.12.17.jar ./samples
23+
java -jar log4j-detector-2021.12.20.jar ./samples
2424
25-
-- github.com/mergebase/log4j-detector v2021.12.17 (by mergebase.com) analyzing paths (could take a while).
25+
-- github.com/mergebase/log4j-detector v2021.12.20 (by mergebase.com) analyzing paths (could take a while).
2626
-- Note: specify the '--verbose' flag to have every file examined printed to STDERR.
2727
/opt/mergebase/log4j-detector/samples/clt-1.0-SNAPSHOT.jar contains Log4J-2.x >= 2.10.0 _VULNERABLE_ :-(
2828
/opt/mergebase/log4j-detector/samples/infinispan-embedded-query-8.2.12.Final.jar contains Log4J-2.x >= 2.0-beta9 (< 2.10.0) _VULNERABLE_ :-(
@@ -85,15 +85,15 @@ your system (e.g., 1 GB or larger).
8585
# Usage
8686

8787
```
88-
java -jar log4j-detector-2021.12.17.jar
88+
java -jar log4j-detector-2021.12.20.jar
8989
90-
Usage: java -jar log4j-detector-2021.12.17.jar [--verbose] [paths to scan...]
90+
Usage: java -jar log4j-detector-2021.12.20.jar [--verbose] [paths to scan...]
9191
9292
Exit codes: 0 = No vulnerable Log4J versions found.
9393
1 = At least one legacy Log4J 1.x version found.
9494
2 = At least one vulnerable Log4J version found.
9595
96-
About - MergeBase log4j detector (version 2021.12.17)
96+
About - MergeBase log4j detector (version 2021.12.20)
9797
Docs - https://github.com/mergebase/log4j-detector
9898
(C) Copyright 2021 Mergebase Software Inc. Licensed to you via GPLv3.
9999
```
@@ -104,7 +104,7 @@ Docs - https://github.com/mergebase/log4j-detector
104104
git clone https://github.com/mergebase/log4j-detector.git
105105
cd log4j-detector/
106106
mvn install
107-
java -jar target/log4j-detector-2021.12.17.jar
107+
java -jar target/log4j-detector-2021.12.20.jar
108108
```
109109
# Testing:
110110

log4j-detector-2021.12.20.jar

58.2 KB
Binary file not shown.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<modelVersion>4.0.0</modelVersion>
66
<groupId>com.mergebase</groupId>
77
<artifactId>log4j-detector</artifactId>
8-
<version>2021.12.17</version>
8+
<version>2021.12.20</version>
99
<licenses>
1010
<license>
1111
<name>GPL-3.0-only</name>

src/main/java/com/mergebase/log4j/Log4JDetector.java

Lines changed: 89 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@
2525
import java.util.Comparator;
2626
import java.util.HashSet;
2727
import java.util.Iterator;
28+
import java.util.LinkedHashMap;
2829
import java.util.List;
2930
import java.util.Locale;
31+
import java.util.Map;
3032
import java.util.Properties;
33+
import java.util.Set;
34+
import java.util.TreeSet;
3135
import java.util.zip.ZipEntry;
3236
import java.util.zip.ZipInputStream;
3337

@@ -68,22 +72,48 @@ public class Log4JDetector {
6872

6973
private static boolean verbose = false;
7074
private static boolean debug = false;
75+
private static boolean json = false;
76+
private static Set<String> excludes = new TreeSet<String>();
7177
private static boolean foundHits = false;
7278
private static boolean foundLog4j1 = false;
7379

74-
public static void main(String[] args) {
80+
public static void main(String[] args) throws IOException {
7581
List<String> argsList = new ArrayList<String>();
7682
Collections.addAll(argsList, args);
7783

7884
Iterator<String> it = argsList.iterator();
85+
List<String> stdinLines = new ArrayList<String>();
7986
while (it.hasNext()) {
80-
final String argOrig = it.next();
87+
final String argOrig = it.next().trim();
8188
if ("--debug".equals(argOrig)) {
8289
debug = true;
8390
it.remove();
8491
} else if ("--verbose".equals(argOrig)) {
8592
verbose = true;
8693
it.remove();
94+
} else if ("--json".equals(argOrig)) {
95+
json = true;
96+
it.remove();
97+
} else if (argOrig.startsWith("--exclude=[")) {
98+
int x = argOrig.indexOf("]");
99+
if (x > 0) {
100+
it.remove();
101+
String json = argOrig.substring("--exclude=".length());
102+
Object o = Java2Json.parse(json);
103+
if (o instanceof List) {
104+
List<Object> list = (List) o;
105+
for (Object obj : list) {
106+
if (obj != null) {
107+
excludes.add(String.valueOf(obj));
108+
}
109+
}
110+
}
111+
}
112+
} else if ("--stdin".equals(argOrig)) {
113+
it.remove();
114+
byte[] b = Bytes.streamToBytes(System.in);
115+
String s = new String(b, Bytes.UTF_8);
116+
stdinLines = Strings.intoLines(s);
87117
} else {
88118
File f = new File(argOrig);
89119
if (!f.exists()) {
@@ -92,28 +122,41 @@ public static void main(String[] args) {
92122
}
93123
}
94124
}
125+
argsList.addAll(stdinLines);
95126

96127
if (argsList.isEmpty()) {
97128
System.out.println();
98-
System.out.println("Usage: java -jar log4j-detector-2021.12.17.jar [--verbose] [paths to scan...]");
129+
System.out.println("Usage: java -jar log4j-detector-2021.12.20.jar [--verbose] [--json] [--stdin] [--exclude=X] [paths to scan...]");
130+
System.out.println();
131+
System.out.println(" --json - Output STDOUT results in JSON. (Errors/warning still emitted to STDERR)");
132+
System.out.println(" --stdin - Parse STDIN for paths to explore.");
133+
System.out.println(" --exclude=X - Where X is a JSON list containing full paths to exclude. Must be valid JSON.");
134+
System.out.println();
135+
System.out.println(" Example: --excludes=[\"/dev\", \"/media\", \"Z:\\TEMP\"]");
99136
System.out.println();
100137
System.out.println("Exit codes: 0 = No vulnerable Log4J versions found.");
101138
System.out.println(" 1 = At least one legacy Log4J 1.x version found.");
102139
System.out.println(" 2 = At least one vulnerable Log4J 2.x version found.");
103140
System.out.println();
104-
System.out.println("About - MergeBase log4j detector (version 2021.12.17)");
141+
System.out.println("About - MergeBase log4j detector (version 2021.12.20)");
105142
System.out.println("Docs - https://github.com/mergebase/log4j-detector ");
106143
System.out.println("(C) Copyright 2021 Mergebase Software Inc. Licensed to you via GPLv3.");
107144
System.out.println();
108145
System.exit(100);
109146
}
110147

111-
System.out.println("-- github.com/mergebase/log4j-detector v2021.12.17 (by mergebase.com) analyzing paths (could take a while).");
112-
System.out.println("-- Note: specify the '--verbose' flag to have every file examined printed to STDERR.");
148+
System.err.println("-- github.com/mergebase/log4j-detector v2021.12.20 (by mergebase.com) analyzing paths (could take a while).");
149+
System.err.println("-- Note: specify the '--verbose' flag to have every file examined printed to STDERR.");
150+
if (json) {
151+
System.out.println("{\"hits\":[");
152+
}
113153
for (String arg : argsList) {
114154
File dir = new File(arg);
115155
analyze(dir);
116156
}
157+
if (json) {
158+
System.out.println("{\"_THE_END_\":true}]}");
159+
}
117160
if (foundHits) {
118161
System.exit(2);
119162
} else if (foundLog4j1) {
@@ -422,10 +465,10 @@ public void close() {
422465
StringBuilder buf = new StringBuilder();
423466
if (isLog4j) {
424467
if (isLog4J1_X) {
425-
buf.append(zipPath).append(" contains Log4J-1.x AND Log4J-2.x _CRAZY_ ");
468+
buf.append(" contains Log4J-1.x AND Log4J-2.x _CRAZY_ ");
426469
foundLog4j1 = true;
427470
} else {
428-
buf.append(zipPath).append(" contains Log4J-2.x ");
471+
buf.append(" contains Log4J-2.x ");
429472
}
430473
if (isVulnerable) {
431474
if (isLog4j_2_10_0) {
@@ -455,11 +498,11 @@ public void close() {
455498
if (!isSafe) {
456499
foundHits = true;
457500
}
458-
System.out.println(buf);
501+
System.out.println(prepareOutput(zipPath, buf));
459502
} else if (isLog4J1_X) {
460-
buf.append(zipPath).append(" contains Log4J-1.x <= 1.2.17 _OLD_");
503+
buf.append(" contains Log4J-1.x <= 1.2.17 _OLD_");
461504
foundLog4j1 = true;
462-
System.out.println(buf);
505+
System.out.println(prepareOutput(zipPath, buf));
463506
}
464507
}
465508
} finally {
@@ -469,6 +512,24 @@ public void close() {
469512
}
470513
}
471514

515+
private static String prepareOutput(String zipPath, StringBuilder buf) {
516+
if (json) {
517+
String msg = buf.toString().trim();
518+
int x = msg.lastIndexOf(" _");
519+
String status = "_UNKNOWN_";
520+
if (x >= 0) {
521+
status = msg.substring(x).trim();
522+
msg = msg.substring(0, x).trim();
523+
}
524+
Map<String, String> m = new LinkedHashMap<String, String>();
525+
m.put(status, zipPath);
526+
m.put("info", msg);
527+
return Java2Json.format(m) + ",";
528+
} else {
529+
return zipPath + buf;
530+
}
531+
}
532+
472533
private static boolean containsMatch(byte[] bytes, byte[] needle) {
473534
int matched = Bytes.kmp(bytes, needle);
474535
return matched >= 0;
@@ -590,6 +651,19 @@ private static void analyze(File f) {
590651
// Hopefully this stops symlink cycles.
591652
// Using CRC-64 of path to save on memory (since we're storing *EVERY* path we come across).
592653
String path = f.getPath();
654+
if (excludes.contains(path)) {
655+
System.err.println("-- Info: Skipping [" + path + "] because --excludes mentions it.");
656+
return;
657+
}
658+
File parent = f.getParentFile();
659+
while (parent != null) {
660+
String parentPath = parent.getPath();
661+
if (excludes.contains(parentPath)) {
662+
System.err.println("-- Info: Skipping [" + path + "] because --excludes mentions it.");
663+
return;
664+
}
665+
parent = parent.getParentFile();
666+
}
593667
long crc = CRC64.hash(path);
594668
if (visited.contains(crc)) {
595669
return;
@@ -626,8 +700,8 @@ private static void analyze(File f) {
626700
if (isLog4J_1_X) {
627701
StringBuilder buf = new StringBuilder();
628702
String grandParent = f.getParentFile().getParent();
629-
buf.append(grandParent).append(" contains contains Log4J-1.x <= 1.2.17 _OLD_ :-|");
630-
System.out.println(buf);
703+
buf.append(" contains Log4J-1.x <= 1.2.17 _OLD_ :-|");
704+
System.out.println(prepareOutput(grandParent, buf));
631705
} else {
632706
maybe = currentPathLower.endsWith(FILE_LOG4J_1);
633707
}
@@ -683,7 +757,7 @@ private static void analyze(File f) {
683757
}
684758
}
685759
StringBuilder buf = new StringBuilder();
686-
buf.append(f.getParentFile().getParent()).append(" contains Log4J-2.x ");
760+
buf.append(" contains Log4J-2.x ");
687761
if (isVulnerable) {
688762
if (isLog4J_2_10) {
689763
if (isLog4J_2_17) {
@@ -711,7 +785,7 @@ private static void analyze(File f) {
711785
} else {
712786
buf.append("<= 2.0-beta8 _POTENTIALLY_SAFE_ (Did you remove JndiLookup.class?)");
713787
}
714-
System.out.println(buf);
788+
System.out.println(prepareOutput(f.getParentFile().getParent(), buf));
715789
}
716790
} else if (verbose) {
717791
System.err.println("-- Skipping " + f.getPath() + " - Not a zip/jar/war file.");

0 commit comments

Comments
 (0)