1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.reporting;
19
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import org.owasp.dependencycheck.dependency.Dependency;
25 import org.owasp.dependencycheck.dependency.Vulnerability;
26 import org.owasp.dependencycheck.dependency.naming.CpeIdentifier;
27 import org.owasp.dependencycheck.dependency.naming.GenericIdentifier;
28 import org.owasp.dependencycheck.dependency.naming.Identifier;
29 import org.owasp.dependencycheck.dependency.naming.PurlIdentifier;
30 import org.owasp.dependencycheck.utils.SeverityUtil;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import us.springett.parsers.cpe.Cpe;
34 import us.springett.parsers.cpe.exceptions.CpeEncodingException;
35 import us.springett.parsers.cpe.util.Convert;
36
37
38
39
40
41
42 public class ReportTool {
43
44
45
46
47 private static final Logger LOGGER = LoggerFactory.getLogger(ReportTool.class);
48
49
50
51
52
53
54
55
56 public String identifierToSuppressionId(Identifier id) {
57 if (id instanceof PurlIdentifier) {
58 final PurlIdentifier purl = (PurlIdentifier) id;
59 return purl.toString();
60 } else if (id instanceof CpeIdentifier) {
61 try {
62 final CpeIdentifier cpeId = (CpeIdentifier) id;
63 final Cpe cpe = cpeId.getCpe();
64 return String.format("cpe:/%s:%s:%s", Convert.wellFormedToCpeUri(cpe.getPart()),
65 Convert.wellFormedToCpeUri(cpe.getWellFormedVendor()),
66 Convert.wellFormedToCpeUri(cpe.getWellFormedProduct()));
67 } catch (CpeEncodingException ex) {
68 LOGGER.debug("Unable to convert to cpe URI", ex);
69 }
70 } else if (id instanceof GenericIdentifier) {
71 return id.getValue();
72 }
73 return null;
74 }
75
76
77
78
79
80
81
82 public Double estimateSeverity(String severity) {
83 return SeverityUtil.estimateCvssV2(severity);
84 }
85
86
87
88
89
90
91
92 public Collection<SarifRule> convertToSarifRules(List<Dependency> dependencies) {
93 final Map<String, SarifRule> rules = new HashMap<>();
94 for (Dependency d : dependencies) {
95 for (Vulnerability v : d.getVulnerabilities()) {
96 if (!rules.containsKey(v.getName())) {
97 final SarifRule r = new SarifRule(v.getName(),
98 buildShortDescription(d, v, v.getKnownExploitedVulnerability() != null),
99 buildDescription(v.getDescription(), v.getKnownExploitedVulnerability()),
100 v.getSource().name(),
101 v.getCvssV2(),
102 v.getCvssV3());
103 rules.put(v.getName(), r);
104 }
105 }
106 }
107 return rules.values();
108 }
109
110 private String determineScore(Vulnerability vuln) {
111 if (vuln.getUnscoredSeverity() != null) {
112 if ("0.0".equals(vuln.getUnscoredSeverity())) {
113 return "unknown";
114 } else {
115 return normalizeSeverity(vuln.getUnscoredSeverity().toLowerCase());
116 }
117 } else if (vuln.getCvssV3() != null && vuln.getCvssV3().getCvssData().getBaseSeverity() != null) {
118 return normalizeSeverity(vuln.getCvssV3().getCvssData().getBaseSeverity().value().toLowerCase());
119 } else if (vuln.getCvssV2() != null && vuln.getCvssV2().getCvssData().getBaseSeverity() != null) {
120 return normalizeSeverity(vuln.getCvssV2().getCvssData().getBaseSeverity());
121 }
122 return "unknown";
123 }
124
125
126
127
128
129
130 public String normalizeSeverity(String sev) {
131 switch (sev.toLowerCase()) {
132 case "critical":
133 return "critical";
134 case "high":
135 return "high";
136 case "medium":
137 case "moderate":
138 return "medium";
139 case "low":
140 case "informational":
141 case "info":
142 return "low";
143 default:
144 return "unknown";
145 }
146 }
147
148
149
150
151
152
153
154
155
156 private String buildShortDescription(Dependency d, Vulnerability vuln, boolean knownExploited) {
157 final StringBuilder sb = new StringBuilder();
158 sb.append(determineScore(vuln))
159 .append(" severity - ")
160 .append(vuln.getName());
161 if (vuln.getCwes() != null && !vuln.getCwes().isEmpty()) {
162 final String cwe = vuln.getCwes().getFullCwes().values().iterator().next();
163 if (cwe != null && !"NVD-CWE-Other".equals(cwe) && !"NVD-CWE-noinfo".equals(cwe)) {
164 sb.append(" ").append(cwe);
165 }
166 }
167 sb.append(" vulnerability in ");
168 if (d.getSoftwareIdentifiers() != null && !d.getSoftwareIdentifiers().isEmpty()) {
169 sb.append(d.getSoftwareIdentifiers().iterator().next());
170 } else {
171 sb.append(d.getDisplayFileName());
172 }
173 if (knownExploited) {
174 sb.append(" *Known Exploited Vulnerability*");
175 }
176 return sb.toString();
177 }
178
179 private String buildDescription(String description,
180 org.owasp.dependencycheck.data.knownexploited.json.Vulnerability knownExploitedVulnerability) {
181 final StringBuilder sb = new StringBuilder();
182 if (knownExploitedVulnerability != null) {
183 sb.append("CISA Known Exploited Vulnerability\n");
184 if (knownExploitedVulnerability.getVendorProject() != null) {
185 sb.append("Vendor/Project: ").append(knownExploitedVulnerability.getVendorProject()).append("\n");
186 }
187 if (knownExploitedVulnerability.getProduct() != null) {
188 sb.append("Product: ").append(knownExploitedVulnerability.getProduct()).append("\n");
189 }
190 if (knownExploitedVulnerability.getVulnerabilityName() != null) {
191 sb.append("Vulnerability Name: ").append(knownExploitedVulnerability.getVulnerabilityName()).append("\n");
192 }
193 if (knownExploitedVulnerability.getDateAdded() != null) {
194 sb.append("Date Added: ").append(knownExploitedVulnerability.getDateAdded()).append("\n");
195 }
196 if (knownExploitedVulnerability.getShortDescription() != null) {
197 sb.append("Short Description: ").append(knownExploitedVulnerability.getShortDescription()).append("\n");
198 }
199 if (knownExploitedVulnerability.getRequiredAction() != null) {
200 sb.append("Required Action: ").append(knownExploitedVulnerability.getRequiredAction()).append("\n");
201 }
202 if (knownExploitedVulnerability.getDueDate() != null) {
203 sb.append("Due Date").append(knownExploitedVulnerability.getDueDate()).append("\n");
204 }
205 if (knownExploitedVulnerability.getNotes() != null) {
206 sb.append("Notes: ").append(knownExploitedVulnerability.getNotes()).append("\n");
207 }
208 sb.append("\n");
209 }
210 sb.append(description);
211 return sb.toString();
212 }
213 }