Skip to content

Commit

Permalink
Print exclude list for --all-drives and --drives options, Reduced zip…
Browse files Browse the repository at this point in the history
… open error, v2.3.4
  • Loading branch information
xeraph committed Dec 19, 2021
1 parent a1eaa9c commit 0534a62
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 36 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
log4j2-scan is a single binary command-line tool for CVE-2021-44228 vulnerability scanning and mitigation patch. It also supports nested JAR file scanning and patch. It also detects CVE-2021-45046 (log4j 2.15.0), CVE-2021-45105 (log4j 2.16.0), CVE-2021-4104 (log4j 1.x), and CVE-2021-42550 (logback 0.9-1.2.7) vulnerabilities.

### Download
* [log4j2-scan 2.3.3 (Windows x64, 7z)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.3/logpresso-log4j2-scan-2.3.3-win64.7z)
* [log4j2-scan 2.3.3 (Windows x64, zip)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.3/logpresso-log4j2-scan-2.3.3-win64.zip)
* [log4j2-scan 2.3.4 (Windows x64, 7z)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.4/logpresso-log4j2-scan-2.3.4-win64.7z)
* [log4j2-scan 2.3.4 (Windows x64, zip)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.4/logpresso-log4j2-scan-2.3.4-win64.zip)
* If you get `VCRUNTIME140.dll not found` error, install [Visual C++ Redistributable](https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170).
* If native executable doesn't work, use the JAR instead. 32bit is not supported.
* 7zip is available from www.7zip.org, and is open source and free.
* [log4j2-scan 2.3.3 (Linux x64)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.3/logpresso-log4j2-scan-2.3.3-linux.tar.gz)
* [log4j2-scan 2.3.3 (Linux aarch64)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.3/logpresso-log4j2-scan-2.3.3-linux-aarch64.tar.gz)
* [log4j2-scan 2.3.4 (Linux x64)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.4/logpresso-log4j2-scan-2.3.4-linux.tar.gz)
* [log4j2-scan 2.3.4 (Linux aarch64)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.4/logpresso-log4j2-scan-2.3.4-linux-aarch64.tar.gz)
* If native executable doesn't work, use the JAR instead. 32bit is not supported.
* [log4j2-scan 2.3.3 (Mac OS)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.3/logpresso-log4j2-scan-2.3.3-darwin.tar.gz)
* [log4j2-scan 2.3.3 (Any OS, 20KB)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.3/logpresso-log4j2-scan-2.3.3.jar)
* [log4j2-scan 2.3.4 (Mac OS)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.4/logpresso-log4j2-scan-2.3.4-darwin.tar.gz)
* [log4j2-scan 2.3.4 (Any OS, 20KB)](https://github.com/logpresso/CVE-2021-44228-Scanner/releases/download/v2.3.4/logpresso-log4j2-scan-2.3.4.jar)

### Build
* [How to build Native Image](https://github.com/logpresso/CVE-2021-44228-Scanner/wiki/FAQ#how-to-build-native-image)
Expand All @@ -22,7 +22,7 @@ Just run log4j2-scan.exe or log4j2-scan with target directory path. The logpress

Usage
```
Logpresso CVE-2021-44228 Vulnerability Scanner 2.3.3 (2021-12-19)
Logpresso CVE-2021-44228 Vulnerability Scanner 2.3.4 (2021-12-19)
Usage: log4j2-scan [--scan-log4j1] [--fix] target_path1 target_path2
-f [config_file_path]
Expand Down Expand Up @@ -85,7 +85,7 @@ On Linux
```
On UNIX (AIX, Solaris, and so on)
```
java -jar logpresso-log4j2-scan-2.3.3.jar [--fix] target_path
java -jar logpresso-log4j2-scan-2.3.4.jar [--fix] target_path
```

If you add `--fix` option, this program will copy vulnerable original JAR file to .bak file, and create new JAR file without `org/apache/logging/log4j/core/lookup/JndiLookup.class` entry. In most environments, JNDI lookup feature will not be used. However, you must use this option at your own risk. Depending the Operating System:
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.logpresso</groupId>
<artifactId>log4j2-scanner</artifactId>
<version>2.3.3</version>
<version>2.3.4</version>
<packaging>jar</packaging>
<name>Logpresso Log4j2 Scanner</name>

Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/logpresso/scanner/DetectResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public void merge(DetectResult result) {
potentiallyVulnerableLog4j1 |= result.isPotentiallyVulnerableLog4j1();
potentiallyVulnerableLog4j2 |= result.isPotentiallyVulnerableLog4j2();
potentiallyVulnerableLogback |= result.isPotentiallyVulnerableLogback();
nestedJar = true;
}

public boolean isVulnerable() {
Expand Down
60 changes: 41 additions & 19 deletions src/main/java/com/logpresso/scanner/Detector.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.logpresso.scanner.utils.DummyInputStream;
import com.logpresso.scanner.utils.IoUtils;
import com.logpresso.scanner.utils.StringUtils;
import com.logpresso.scanner.utils.ZipFileIterator;
import com.logpresso.scanner.utils.ZipUtils;

public class Detector {
Expand Down Expand Up @@ -109,19 +110,26 @@ protected void scanJarFile(File jarFile, boolean fix) {
InputStream is = null;

Charset altCharset = null;
ZipFileIterator it = null;
try {
is = new FileInputStream(jarFile);
DetectResult result = null;

try {
result = scanStream(jarFile, is, new ArrayList<String>(), Charset.forName("utf-8"));
it = openZipFileIterator(jarFile, is);
result = scanStream(jarFile, it, new ArrayList<String>(), Charset.forName("utf-8"));
} catch (IllegalArgumentException e) {
// second try with system encoding or alternative encoding
altCharset = Charset.defaultCharset();
if (config.getZipCharset() != null)
altCharset = config.getZipCharset();

result = scanStream(jarFile, is, new ArrayList<String>(), altCharset);
IoUtils.ensureClose(it);
IoUtils.ensureClose(is);
is = new FileInputStream(jarFile);

it = openZipFileIterator(jarFile, is);
result = scanStream(jarFile, it, new ArrayList<String>(), altCharset);
}

if (result.isVulnerable())
Expand Down Expand Up @@ -154,12 +162,23 @@ else if (result.isPotentiallyVulnerable())
if (config.isDebug())
t.printStackTrace();
} finally {
IoUtils.ensureClose(it);
IoUtils.ensureClose(is);
}
}

private DetectResult scanStream(File jarFile, InputStream is, List<String> pathChain, Charset charset) throws IOException {
ZipInputStream zis = null;
private ZipFileIterator openZipFileIterator(File jarFile, InputStream is) throws IOException {
// Try to avoid 'only DEFLATED entries can have EXT descriptor' error
// See https://bugs.openjdk.java.net/browse/JDK-8143613
if (jarFile.getName().endsWith(".zip")) {
return new ZipFileIterator(jarFile);
} else {
return new ZipFileIterator(new ZipInputStream(new DummyInputStream(is)));
}
}

private DetectResult scanStream(File jarFile, ZipFileIterator it, List<String> pathChain, Charset charset)
throws IOException {
DetectResult result = new DetectResult();
String log4j2Version = null;
String log4j1Version = null;
Expand All @@ -178,15 +197,14 @@ private DetectResult scanStream(File jarFile, InputStream is, List<String> pathC
Set<String> shadedJmsAppenderPaths = new TreeSet<String>();

try {
zis = new ZipInputStream(new DummyInputStream(is));

while (true) {
ZipEntry entry = zis.getNextEntry();
ZipEntry entry = it.getNextEntry();
if (entry == null)
break;

InputStream is = it.getNextInputStream();
if (entry.getName().equals(LOG4J_CORE_POM_PROPS))
log4j2Version = loadVulnerableLog4jVersion(zis);
log4j2Version = loadVulnerableLog4jVersion(is);

if (entry.getName().equals(JNDI_LOOKUP_CLASS_PATH))
log4j2Mitigated = false;
Expand All @@ -196,7 +214,7 @@ private DetectResult scanStream(File jarFile, InputStream is, List<String> pathC

if (config.isScanForLog4j1()) {
if (entry.getName().equals(LOG4J_12_CORE_POM_PROPS))
log4j1Version = loadVulnerableLog4j1(zis);
log4j1Version = loadVulnerableLog4j1(is);

if (entry.getName().equals(LOG4J_12_JMSAPPENDER))
foundJmsAppender = true;
Expand All @@ -207,19 +225,25 @@ private DetectResult scanStream(File jarFile, InputStream is, List<String> pathC

if (config.isScanForLogback()) {
if (entry.getName().equals(LOGBACK_CLASSIC_POM_PROPS))
logbackVersion = loadVulnerableLogback(zis);
logbackVersion = loadVulnerableLogback(is);

if (entry.getName().equals(LOGBACK_JNDI_CLASS_PATH))
foundJndiUtil = true;
}

if (ZipUtils.isScanTarget(entry.getName(), config.isScanZip())) {
pathChain.add(entry.getName());

DetectResult nestedResult = scanStream(jarFile, zis, pathChain, charset);
result.merge(nestedResult);

pathChain.remove(pathChain.size() - 1);
ZipFileIterator nestedIt = null;
try {
nestedIt = new ZipFileIterator(new ZipInputStream(new DummyInputStream(is)));
pathChain.add(entry.getName());

DetectResult nestedResult = scanStream(jarFile, nestedIt, pathChain, charset);
result.merge(nestedResult);

pathChain.remove(pathChain.size() - 1);
} finally {
IoUtils.ensureClose(nestedIt);
}
}
}

Expand Down Expand Up @@ -264,8 +288,6 @@ private DetectResult scanStream(File jarFile, InputStream is, List<String> pathC
return result;

throw e;
} finally {
IoUtils.ensureClose(zis);
}
}

Expand All @@ -274,7 +296,7 @@ private boolean isWinRarFile(File jarFile, List<String> pathChain) {
if (pathChain.isEmpty())
fileName = jarFile.getName();
else
pathChain.get(pathChain.size() - 1);
fileName = pathChain.get(pathChain.size() - 1);

return fileName.toLowerCase().endsWith(".rar");
}
Expand Down
27 changes: 19 additions & 8 deletions src/main/java/com/logpresso/scanner/Log4j2Scanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import com.logpresso.scanner.utils.ZipUtils;

public class Log4j2Scanner {
private static final String BANNER = "Logpresso CVE-2021-44228 Vulnerability Scanner 2.3.3 (2021-12-19)";
private static final String BANNER = "Logpresso CVE-2021-44228 Vulnerability Scanner 2.3.4 (2021-12-20)";

private static final boolean isWindows = File.separatorChar == '\\';

Expand Down Expand Up @@ -100,16 +100,24 @@ public void run() throws IOException {
allDrives.add(drive.getPath());
}

System.out.println("Scanning drives: " + StringUtils.join(allDrives, ", "));
System.out.println("Scanning drives: " + StringUtils.join(allDrives, ", ") + getExcludeDescription());
System.out.println("");

for (String drivePath : allDrives)
traverse(new File(drivePath));
} else if (!config.getDriveLetters().isEmpty()) {

List<String> drives = new ArrayList<String>();
for (File drive : config.getDriveLetters())
drives.add(drive.getAbsolutePath());

System.out.println("Scanning drives: " + StringUtils.join(drives, ", ") + getExcludeDescription());
System.out.println("");

for (File drive : config.getDriveLetters())
traverse(drive);
} else if (config.getIncludeFilePath() != null) {
System.out.println("Scanning files in " + config.getIncludeFilePath());
System.out.println("Scanning files in " + config.getIncludeFilePath() + getExcludeDescription());
System.out.println("");

BufferedReader br = null;
Expand All @@ -134,12 +142,8 @@ public void run() throws IOException {
}

} else {
String excludeMsg = "";
if (!config.getExcludePaths().isEmpty())
excludeMsg = " (without " + StringUtils.join(config.getExcludePaths(), ", ") + ")";

String targetMsg = StringUtils.join(config.getTargetPaths(), ", ");
System.out.println("Scanning directory: " + targetMsg + excludeMsg);
System.out.println("Scanning directory: " + targetMsg + getExcludeDescription());

for (String targetPath : config.getTargetPaths()) {
File f = new File(targetPath);
Expand Down Expand Up @@ -172,6 +176,13 @@ public void run() throws IOException {
}
}

private String getExcludeDescription() {
String excludeMsg = "";
if (!config.getExcludePaths().isEmpty())
excludeMsg = " (without " + StringUtils.join(config.getExcludePaths(), ", ") + ")";
return excludeMsg;
}

private void fix() {
if (!detector.getVulnerableFiles().isEmpty())
System.out.println("");
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/com/logpresso/scanner/utils/ZipFileIterator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.logpresso.scanner.utils;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

public class ZipFileIterator implements Closeable {

private ZipFile zipFile;
private ZipInputStream zis;
private Enumeration<? extends ZipEntry> e;
private ZipEntry nextEntry;

public ZipFileIterator(File file) throws IOException {
this.zipFile = new ZipFile(file);
e = zipFile.entries();
}

public ZipFileIterator(ZipInputStream zis) {
this.zis = zis;
}

public ZipEntry getNextEntry() throws IOException {
if (zipFile != null) {
if (e.hasMoreElements()) {
this.nextEntry = e.nextElement();
return nextEntry;
} else {
return null;
}
} else {
this.nextEntry = zis.getNextEntry();
return nextEntry;
}
}

public InputStream getNextInputStream() throws IOException {
if (zipFile != null)
return zipFile.getInputStream(nextEntry);

return zis;
}

public void close() throws IOException {
if (zipFile != null)
zipFile.close();

if (zis != null)
IoUtils.ensureClose(zis);
}

}

0 comments on commit 0534a62

Please sign in to comment.