Skip to content

Commit 0534a62

Browse files
committed
Print exclude list for --all-drives and --drives options, Reduced zip open error, v2.3.4
1 parent a1eaa9c commit 0534a62

File tree

6 files changed

+127
-36
lines changed

6 files changed

+127
-36
lines changed

README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
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.
44

55
### Download
6-
* [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)
7-
* [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)
6+
* [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)
7+
* [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)
88
* 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).
99
* If native executable doesn't work, use the JAR instead. 32bit is not supported.
1010
* 7zip is available from www.7zip.org, and is open source and free.
11-
* [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)
12-
* [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)
11+
* [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)
12+
* [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)
1313
* If native executable doesn't work, use the JAR instead. 32bit is not supported.
14-
* [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)
15-
* [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)
14+
* [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)
15+
* [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)
1616

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

2323
Usage
2424
```
25-
Logpresso CVE-2021-44228 Vulnerability Scanner 2.3.3 (2021-12-19)
25+
Logpresso CVE-2021-44228 Vulnerability Scanner 2.3.4 (2021-12-19)
2626
Usage: log4j2-scan [--scan-log4j1] [--fix] target_path1 target_path2
2727
2828
-f [config_file_path]
@@ -85,7 +85,7 @@ On Linux
8585
```
8686
On UNIX (AIX, Solaris, and so on)
8787
```
88-
java -jar logpresso-log4j2-scan-2.3.3.jar [--fix] target_path
88+
java -jar logpresso-log4j2-scan-2.3.4.jar [--fix] target_path
8989
```
9090

9191
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:

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<modelVersion>4.0.0</modelVersion>
77
<groupId>com.logpresso</groupId>
88
<artifactId>log4j2-scanner</artifactId>
9-
<version>2.3.3</version>
9+
<version>2.3.4</version>
1010
<packaging>jar</packaging>
1111
<name>Logpresso Log4j2 Scanner</name>
1212

src/main/java/com/logpresso/scanner/DetectResult.java

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public void merge(DetectResult result) {
1414
potentiallyVulnerableLog4j1 |= result.isPotentiallyVulnerableLog4j1();
1515
potentiallyVulnerableLog4j2 |= result.isPotentiallyVulnerableLog4j2();
1616
potentiallyVulnerableLogback |= result.isPotentiallyVulnerableLogback();
17+
nestedJar = true;
1718
}
1819

1920
public boolean isVulnerable() {

src/main/java/com/logpresso/scanner/Detector.java

+41-19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.logpresso.scanner.utils.DummyInputStream;
2222
import com.logpresso.scanner.utils.IoUtils;
2323
import com.logpresso.scanner.utils.StringUtils;
24+
import com.logpresso.scanner.utils.ZipFileIterator;
2425
import com.logpresso.scanner.utils.ZipUtils;
2526

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

111112
Charset altCharset = null;
113+
ZipFileIterator it = null;
112114
try {
113115
is = new FileInputStream(jarFile);
114116
DetectResult result = null;
115117

116118
try {
117-
result = scanStream(jarFile, is, new ArrayList<String>(), Charset.forName("utf-8"));
119+
it = openZipFileIterator(jarFile, is);
120+
result = scanStream(jarFile, it, new ArrayList<String>(), Charset.forName("utf-8"));
118121
} catch (IllegalArgumentException e) {
119122
// second try with system encoding or alternative encoding
120123
altCharset = Charset.defaultCharset();
121124
if (config.getZipCharset() != null)
122125
altCharset = config.getZipCharset();
123126

124-
result = scanStream(jarFile, is, new ArrayList<String>(), altCharset);
127+
IoUtils.ensureClose(it);
128+
IoUtils.ensureClose(is);
129+
is = new FileInputStream(jarFile);
130+
131+
it = openZipFileIterator(jarFile, is);
132+
result = scanStream(jarFile, it, new ArrayList<String>(), altCharset);
125133
}
126134

127135
if (result.isVulnerable())
@@ -154,12 +162,23 @@ else if (result.isPotentiallyVulnerable())
154162
if (config.isDebug())
155163
t.printStackTrace();
156164
} finally {
165+
IoUtils.ensureClose(it);
157166
IoUtils.ensureClose(is);
158167
}
159168
}
160169

161-
private DetectResult scanStream(File jarFile, InputStream is, List<String> pathChain, Charset charset) throws IOException {
162-
ZipInputStream zis = null;
170+
private ZipFileIterator openZipFileIterator(File jarFile, InputStream is) throws IOException {
171+
// Try to avoid 'only DEFLATED entries can have EXT descriptor' error
172+
// See https://bugs.openjdk.java.net/browse/JDK-8143613
173+
if (jarFile.getName().endsWith(".zip")) {
174+
return new ZipFileIterator(jarFile);
175+
} else {
176+
return new ZipFileIterator(new ZipInputStream(new DummyInputStream(is)));
177+
}
178+
}
179+
180+
private DetectResult scanStream(File jarFile, ZipFileIterator it, List<String> pathChain, Charset charset)
181+
throws IOException {
163182
DetectResult result = new DetectResult();
164183
String log4j2Version = null;
165184
String log4j1Version = null;
@@ -178,15 +197,14 @@ private DetectResult scanStream(File jarFile, InputStream is, List<String> pathC
178197
Set<String> shadedJmsAppenderPaths = new TreeSet<String>();
179198

180199
try {
181-
zis = new ZipInputStream(new DummyInputStream(is));
182-
183200
while (true) {
184-
ZipEntry entry = zis.getNextEntry();
201+
ZipEntry entry = it.getNextEntry();
185202
if (entry == null)
186203
break;
187204

205+
InputStream is = it.getNextInputStream();
188206
if (entry.getName().equals(LOG4J_CORE_POM_PROPS))
189-
log4j2Version = loadVulnerableLog4jVersion(zis);
207+
log4j2Version = loadVulnerableLog4jVersion(is);
190208

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

197215
if (config.isScanForLog4j1()) {
198216
if (entry.getName().equals(LOG4J_12_CORE_POM_PROPS))
199-
log4j1Version = loadVulnerableLog4j1(zis);
217+
log4j1Version = loadVulnerableLog4j1(is);
200218

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

208226
if (config.isScanForLogback()) {
209227
if (entry.getName().equals(LOGBACK_CLASSIC_POM_PROPS))
210-
logbackVersion = loadVulnerableLogback(zis);
228+
logbackVersion = loadVulnerableLogback(is);
211229

212230
if (entry.getName().equals(LOGBACK_JNDI_CLASS_PATH))
213231
foundJndiUtil = true;
214232
}
215233

216234
if (ZipUtils.isScanTarget(entry.getName(), config.isScanZip())) {
217-
pathChain.add(entry.getName());
218-
219-
DetectResult nestedResult = scanStream(jarFile, zis, pathChain, charset);
220-
result.merge(nestedResult);
221-
222-
pathChain.remove(pathChain.size() - 1);
235+
ZipFileIterator nestedIt = null;
236+
try {
237+
nestedIt = new ZipFileIterator(new ZipInputStream(new DummyInputStream(is)));
238+
pathChain.add(entry.getName());
239+
240+
DetectResult nestedResult = scanStream(jarFile, nestedIt, pathChain, charset);
241+
result.merge(nestedResult);
242+
243+
pathChain.remove(pathChain.size() - 1);
244+
} finally {
245+
IoUtils.ensureClose(nestedIt);
246+
}
223247
}
224248
}
225249

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

266290
throw e;
267-
} finally {
268-
IoUtils.ensureClose(zis);
269291
}
270292
}
271293

@@ -274,7 +296,7 @@ private boolean isWinRarFile(File jarFile, List<String> pathChain) {
274296
if (pathChain.isEmpty())
275297
fileName = jarFile.getName();
276298
else
277-
pathChain.get(pathChain.size() - 1);
299+
fileName = pathChain.get(pathChain.size() - 1);
278300

279301
return fileName.toLowerCase().endsWith(".rar");
280302
}

src/main/java/com/logpresso/scanner/Log4j2Scanner.java

+19-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import com.logpresso.scanner.utils.ZipUtils;
1616

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

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

@@ -100,16 +100,24 @@ public void run() throws IOException {
100100
allDrives.add(drive.getPath());
101101
}
102102

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

106106
for (String drivePath : allDrives)
107107
traverse(new File(drivePath));
108108
} else if (!config.getDriveLetters().isEmpty()) {
109+
110+
List<String> drives = new ArrayList<String>();
111+
for (File drive : config.getDriveLetters())
112+
drives.add(drive.getAbsolutePath());
113+
114+
System.out.println("Scanning drives: " + StringUtils.join(drives, ", ") + getExcludeDescription());
115+
System.out.println("");
116+
109117
for (File drive : config.getDriveLetters())
110118
traverse(drive);
111119
} else if (config.getIncludeFilePath() != null) {
112-
System.out.println("Scanning files in " + config.getIncludeFilePath());
120+
System.out.println("Scanning files in " + config.getIncludeFilePath() + getExcludeDescription());
113121
System.out.println("");
114122

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

136144
} else {
137-
String excludeMsg = "";
138-
if (!config.getExcludePaths().isEmpty())
139-
excludeMsg = " (without " + StringUtils.join(config.getExcludePaths(), ", ") + ")";
140-
141145
String targetMsg = StringUtils.join(config.getTargetPaths(), ", ");
142-
System.out.println("Scanning directory: " + targetMsg + excludeMsg);
146+
System.out.println("Scanning directory: " + targetMsg + getExcludeDescription());
143147

144148
for (String targetPath : config.getTargetPaths()) {
145149
File f = new File(targetPath);
@@ -172,6 +176,13 @@ public void run() throws IOException {
172176
}
173177
}
174178

179+
private String getExcludeDescription() {
180+
String excludeMsg = "";
181+
if (!config.getExcludePaths().isEmpty())
182+
excludeMsg = " (without " + StringUtils.join(config.getExcludePaths(), ", ") + ")";
183+
return excludeMsg;
184+
}
185+
175186
private void fix() {
176187
if (!detector.getVulnerableFiles().isEmpty())
177188
System.out.println("");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.logpresso.scanner.utils;
2+
3+
import java.io.Closeable;
4+
import java.io.File;
5+
import java.io.IOException;
6+
import java.io.InputStream;
7+
import java.util.Enumeration;
8+
import java.util.zip.ZipEntry;
9+
import java.util.zip.ZipFile;
10+
import java.util.zip.ZipInputStream;
11+
12+
public class ZipFileIterator implements Closeable {
13+
14+
private ZipFile zipFile;
15+
private ZipInputStream zis;
16+
private Enumeration<? extends ZipEntry> e;
17+
private ZipEntry nextEntry;
18+
19+
public ZipFileIterator(File file) throws IOException {
20+
this.zipFile = new ZipFile(file);
21+
e = zipFile.entries();
22+
}
23+
24+
public ZipFileIterator(ZipInputStream zis) {
25+
this.zis = zis;
26+
}
27+
28+
public ZipEntry getNextEntry() throws IOException {
29+
if (zipFile != null) {
30+
if (e.hasMoreElements()) {
31+
this.nextEntry = e.nextElement();
32+
return nextEntry;
33+
} else {
34+
return null;
35+
}
36+
} else {
37+
this.nextEntry = zis.getNextEntry();
38+
return nextEntry;
39+
}
40+
}
41+
42+
public InputStream getNextInputStream() throws IOException {
43+
if (zipFile != null)
44+
return zipFile.getInputStream(nextEntry);
45+
46+
return zis;
47+
}
48+
49+
public void close() throws IOException {
50+
if (zipFile != null)
51+
zipFile.close();
52+
53+
if (zis != null)
54+
IoUtils.ensureClose(zis);
55+
}
56+
57+
}

0 commit comments

Comments
 (0)