1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.data.update;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.net.URISyntaxException;
23 import java.net.URL;
24 import java.sql.SQLException;
25
26 import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
27 import org.apache.hc.core5.http.HttpEntity;
28 import org.apache.hc.core5.http.io.HttpClientResponseHandler;
29 import org.owasp.dependencycheck.Engine;
30 import org.owasp.dependencycheck.data.knownexploited.json.KnownExploitedVulnerabilitiesSchema;
31 import org.owasp.dependencycheck.data.nvdcve.CveDB;
32 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
33 import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
34 import org.owasp.dependencycheck.data.update.cisa.KnownExploitedVulnerabilityParser;
35 import org.owasp.dependencycheck.data.update.exception.CorruptedDatastreamException;
36 import org.owasp.dependencycheck.data.update.exception.UpdateException;
37 import org.owasp.dependencycheck.utils.Downloader;
38 import org.owasp.dependencycheck.utils.ResourceNotFoundException;
39 import org.owasp.dependencycheck.utils.Settings;
40 import org.owasp.dependencycheck.utils.TooManyRequestsException;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44
45
46
47 public class KnownExploitedDataSource implements CachedWebDataSource {
48
49
50
51
52 private static final Logger LOGGER = LoggerFactory.getLogger(KnownExploitedDataSource.class);
53
54
55
56 private static final String DEFAULT_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json";
57
58
59
60 private CveDB cveDB;
61
62
63
64 private Settings settings;
65
66
67
68 private DatabaseProperties dbProperties = null;
69
70 @Override
71 public boolean update(Engine engine) throws UpdateException {
72 this.cveDB = engine.getDatabase();
73 this.settings = engine.getSettings();
74 dbProperties = cveDB.getDatabaseProperties();
75 final boolean autoUpdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
76 final boolean kevEnabled = settings.getBoolean(Settings.KEYS.ANALYZER_KNOWN_EXPLOITED_ENABLED, true);
77 if (autoUpdate && kevEnabled && shouldUpdate()) {
78 try {
79 final URL url = new URL(settings.getString(Settings.KEYS.KEV_URL, DEFAULT_URL));
80 LOGGER.info("Updating CISA Known Exploited Vulnerability list: " + url.toString());
81
82 final HttpClientResponseHandler<KnownExploitedVulnerabilitiesSchema> kevParsingResponseHandler =
83 new AbstractHttpClientResponseHandler<>() {
84 @Override
85 public KnownExploitedVulnerabilitiesSchema handleEntity(HttpEntity entity) throws IOException {
86 try (InputStream in = entity.getContent()) {
87 final KnownExploitedVulnerabilityParser parser = new KnownExploitedVulnerabilityParser();
88 final KnownExploitedVulnerabilitiesSchema data = parser.parse(in);
89 return data;
90 } catch (CorruptedDatastreamException | UpdateException e) {
91 throw new IOException("Error processing response", e);
92 }
93 }
94 };
95
96 final KnownExploitedVulnerabilitiesSchema data = Downloader.getInstance().fetchAndHandle(url, kevParsingResponseHandler);
97 final String currentVersion = dbProperties.getProperty(DatabaseProperties.KEV_VERSION, "");
98 if (!currentVersion.equals(data.getCatalogVersion())) {
99 cveDB.updateKnownExploitedVulnerabilities(data.getVulnerabilities());
100 }
101
102 dbProperties.save(DatabaseProperties.KEV_LAST_CHECKED, Long.toString(System.currentTimeMillis() / 1000));
103 return true;
104 } catch (TooManyRequestsException | ResourceNotFoundException | IOException | DatabaseException
105 | SQLException | URISyntaxException ex) {
106 throw new UpdateException(ex);
107 }
108 }
109 return false;
110 }
111
112 @Override
113 public boolean purge(Engine engine) {
114
115 return true;
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129 private boolean shouldUpdate() throws UpdateException {
130 boolean proceed = true;
131
132 final int validForHours = settings.getInt(Settings.KEYS.KEV_CHECK_VALID_FOR_HOURS, 24);
133 if (cveDB.dataExists() && 0 < validForHours) {
134
135 final long validForSeconds = validForHours * 60L * 60L;
136 final long lastChecked = dbProperties.getPropertyInSeconds(DatabaseProperties.KEV_LAST_CHECKED);
137 final long now = System.currentTimeMillis() / 1000;
138 proceed = (now - lastChecked) > validForSeconds;
139 if (!proceed) {
140 LOGGER.info("Skipping Known Exploited Vulnerabilities update check since last check was within {} hours.", validForHours);
141 }
142 }
143 return proceed;
144 }
145
146 }