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
48 public class KnownExploitedDataSource implements CachedWebDataSource {
49
50
51
52
53 private static final Logger LOGGER = LoggerFactory.getLogger(KnownExploitedDataSource.class);
54
55
56
57 private static final String DEFAULT_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json";
58
59
60
61 private CveDB cveDB;
62
63
64
65 private Settings settings;
66
67
68
69 private DatabaseProperties dbProperties = null;
70
71 @Override
72 public boolean update(Engine engine) throws UpdateException {
73 this.cveDB = engine.getDatabase();
74 this.settings = engine.getSettings();
75 dbProperties = cveDB.getDatabaseProperties();
76 final boolean autoUpdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
77 final boolean kevEnabled = settings.getBoolean(Settings.KEYS.ANALYZER_KNOWN_EXPLOITED_ENABLED, true);
78 if (autoUpdate && kevEnabled && shouldUpdate()) {
79 try {
80 final URL url = new URL(settings.getString(Settings.KEYS.KEV_URL, DEFAULT_URL));
81 LOGGER.info("Updating CISA Known Exploited Vulnerability list: " + url.toString());
82
83 final HttpClientResponseHandler<KnownExploitedVulnerabilitiesSchema> kevParsingResponseHandler
84 = new AbstractHttpClientResponseHandler<>() {
85 @Override
86 public KnownExploitedVulnerabilitiesSchema handleEntity(HttpEntity entity) throws IOException {
87 try (InputStream in = entity.getContent()) {
88 final KnownExploitedVulnerabilityParser parser = new KnownExploitedVulnerabilityParser();
89 final KnownExploitedVulnerabilitiesSchema data = parser.parse(in);
90 return data;
91 } catch (CorruptedDatastreamException | UpdateException e) {
92 throw new IOException("Error processing response", e);
93 }
94 }
95 };
96
97 final KnownExploitedVulnerabilitiesSchema data = Downloader.getInstance().fetchAndHandle(url, kevParsingResponseHandler);
98 final String currentVersion = dbProperties.getProperty(DatabaseProperties.KEV_VERSION, "");
99 if (!currentVersion.equals(data.getCatalogVersion())) {
100 cveDB.updateKnownExploitedVulnerabilities(data.getVulnerabilities());
101 }
102
103 dbProperties.save(DatabaseProperties.KEV_LAST_CHECKED, Long.toString(System.currentTimeMillis() / 1000));
104 return true;
105 } catch (TooManyRequestsException | ResourceNotFoundException | IOException | DatabaseException | 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 }