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.URL;
23 import java.sql.SQLException;
24
25 import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
26 import org.apache.hc.core5.http.HttpEntity;
27 import org.apache.hc.core5.http.io.HttpClientResponseHandler;
28 import org.owasp.dependencycheck.Engine;
29 import org.owasp.dependencycheck.data.knownexploited.json.KnownExploitedVulnerabilitiesSchema;
30 import org.owasp.dependencycheck.data.nvdcve.CveDB;
31 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
32 import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
33 import org.owasp.dependencycheck.data.update.cisa.KnownExploitedVulnerabilityParser;
34 import org.owasp.dependencycheck.data.update.exception.CorruptedDatastreamException;
35 import org.owasp.dependencycheck.data.update.exception.UpdateException;
36 import org.owasp.dependencycheck.utils.Downloader;
37 import org.owasp.dependencycheck.utils.ResourceNotFoundException;
38 import org.owasp.dependencycheck.utils.Settings;
39 import org.owasp.dependencycheck.utils.TooManyRequestsException;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
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 | SQLException ex) {
105 throw new UpdateException(ex);
106 }
107 }
108 return false;
109 }
110
111 @Override
112 public boolean purge(Engine engine) {
113
114 return true;
115 }
116
117
118
119
120
121
122
123
124
125
126
127
128 private boolean shouldUpdate() throws UpdateException {
129 boolean proceed = true;
130
131 final int validForHours = settings.getInt(Settings.KEYS.KEV_CHECK_VALID_FOR_HOURS, 24);
132 if (cveDB.dataExists() && 0 < validForHours) {
133
134 final long validForSeconds = validForHours * 60L * 60L;
135 final long lastChecked = dbProperties.getPropertyInSeconds(DatabaseProperties.KEV_LAST_CHECKED);
136 final long now = System.currentTimeMillis() / 1000;
137 proceed = (now - lastChecked) > validForSeconds;
138 if (!proceed) {
139 LOGGER.info("Skipping Known Exploited Vulnerabilities update check since last check was within {} hours.", validForHours);
140 }
141 }
142 return proceed;
143 }
144
145 }