dradis-calculator_cvss 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ //= require jquery
2
+ //= require bootstrap
3
+ //= require dradis/plugins/calculators/cvss/vendor/cvsscalc30
4
+ //= require dradis/plugins/calculators/cvss/calculator
@@ -0,0 +1,684 @@
1
+ /* Copyright (c) 2015, FIRST.ORG, INC.
2
+ * All rights reserved.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5
+ * following conditions are met:
6
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7
+ * disclaimer.
8
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
9
+ * following disclaimer in the documentation and/or other materials provided with the distribution.
10
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
11
+ * products derived from this software without specific prior written permission.
12
+ *
13
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
14
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
16
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
18
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
19
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20
+ */
21
+
22
+ /* This JavaScript contains two main functions. Both take CVSS metric values and calculate CVSS scores for Base,
23
+ * Temporal and Environmental metric groups, their associated severity ratings, and an overall Vector String.
24
+ *
25
+ * Use CVSS.calculateCVSSFromMetrics if you wish to pass metric values as individual parameters.
26
+ * Use CVSS.calculateCVSSFromVector if you wish to pass metric values as a single Vector String.
27
+ *
28
+ * Changelog
29
+ *
30
+ * 2015-08-04 Darius Wiles Added CVSS.generateXMLFromMetrics and CVSS.generateXMLFromVector functions to return
31
+ * XML string representations of: a set of metric values; or a Vector String respectively.
32
+ * Moved all constants and functions to an object named "CVSS" to
33
+ * reduce the chance of conflicts in global variables when this file is combined with
34
+ * other JavaScript code. This will break all existing code that uses this file until
35
+ * the string "CVSS." is prepended to all references. The "Exploitability" metric has been
36
+ * renamed "Exploit Code Maturity" in the specification, so the same change has been made
37
+ * in the code in this file.
38
+ *
39
+ * 2015-04-24 Darius Wiles Environmental formula modified to eliminate undesirable behavior caused by subtle
40
+ * differences in rounding between Temporal and Environmental formulas that often
41
+ * caused the latter to be 0.1 lower than than the former when all Environmental
42
+ * metrics are "Not defined". Also added a RoundUp1 function to simplify formulas.
43
+ *
44
+ * 2015-04-09 Darius Wiles Added calculateCVSSFromVector function, license information, cleaned up code and improved
45
+ * comments.
46
+ *
47
+ * 2014-12-12 Darius Wiles Initial release for CVSS 3.0 Preview 2.
48
+ */
49
+
50
+ // Constants used in the formula. They are not declared as "const" to avoid problems in older browsers.
51
+
52
+ var CVSS = {};
53
+
54
+ CVSS.CVSSVersionIdentifier = "CVSS:3.0";
55
+ CVSS.exploitabilityCoefficient = 8.22;
56
+ CVSS.scopeCoefficient = 1.08;
57
+
58
+ // A regular expression to validate that a CVSS 3.0 vector string is well formed. It checks metrics and metric
59
+ // values. It does not check that a metric is specified more than once and it does not check that all base
60
+ // metrics are present. These checks need to be performed separately.
61
+
62
+ CVSS.vectorStringRegex_30 = /^CVSS:3\.0\/((AV:[NALP]|AC:[LH]|PR:[UNLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XUNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])\/)*(AV:[NALP]|AC:[LH]|PR:[UNLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XUNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$/;
63
+
64
+
65
+ // Associative arrays mapping each metric value to the constant defined in the CVSS scoring formula in the CVSS v3.0
66
+ // specification.
67
+
68
+ CVSS.Weight = {
69
+ AV: { N: 0.85, A: 0.62, L: 0.55, P: 0.2},
70
+ AC: { H: 0.44, L: 0.77},
71
+ PR: { U: {N: 0.85, L: 0.62, H: 0.27}, // These values are used if Scope is Unchanged
72
+ C: {N: 0.85, L: 0.68, H: 0.5}}, // These values are used if Scope is Changed
73
+ UI: { N: 0.85, R: 0.62},
74
+ S: { U: 6.42, C: 7.52}, // Note: not defined as constants in specification
75
+ CIA: { N: 0, L: 0.22, H: 0.56}, // C, I and A have the same weights
76
+
77
+ E: { X: 1, U: 0.91, P: 0.94, F: 0.97, H: 1},
78
+ RL: { X: 1, O: 0.95, T: 0.96, W: 0.97, U: 1},
79
+ RC: { X: 1, U: 0.92, R: 0.96, C: 1},
80
+
81
+ CIAR: { X: 1, L: 0.5, M: 1, H: 1.5} // CR, IR and AR have the same weights
82
+ };
83
+
84
+
85
+ // Severity rating bands, as defined in the CVSS v3.0 specification.
86
+
87
+ CVSS.severityRatings = [ { name: "None", bottom: 0.0, top: 0.0},
88
+ { name: "Low", bottom: 0.1, top: 3.9},
89
+ { name: "Medium", bottom: 4.0, top: 6.9},
90
+ { name: "High", bottom: 7.0, top: 8.9},
91
+ { name: "Critical", bottom: 9.0, top: 10.0} ];
92
+
93
+
94
+
95
+
96
+ /* ** CVSS.calculateCVSSFromMetrics **
97
+ *
98
+ * Takes Base, Temporal and Environmental metric values as individual parameters. Their values are in the short format
99
+ * defined in the CVSS v3.0 standard definition of the Vector String. For example, the AttackComplexity parameter
100
+ * should be either "H" or "L".
101
+ *
102
+ * Returns Base, Temporal and Environmental scores, severity ratings, and an overall Vector String. All Base metrics
103
+ * are required to generate this output. All Temporal and Environmental metric values are optional. Any that are not
104
+ * passed default to "X" ("Not Defined").
105
+ *
106
+ * The output is an object which always has a property named "success".
107
+ *
108
+ * If no errors are encountered, success is Boolean "true", and the following other properties are defined containing
109
+ * scores, severities and a vector string:
110
+ * baseMetricScore, baseSeverity,
111
+ * temporalMetricScore, temporalSeverity,
112
+ * environmentalMetricScore, environmentalSeverity,
113
+ * vectorString
114
+ *
115
+ * If errors are encountered, success is Boolean "false", and the following other properties are defined:
116
+ * errorType - a string indicating the error. Either:
117
+ * "MissingBaseMetric", if at least one Base metric has not been defined; or
118
+ * "UnknownMetricValue", if at least one metric value is invalid.
119
+ * errorMetrics - an array of strings representing the metrics at fault. The strings are abbreviated versions of the
120
+ * metrics, as defined in the CVSS v3.0 standard definition of the Vector String.
121
+ */
122
+ CVSS.calculateCVSSFromMetrics = function (
123
+ AttackVector, AttackComplexity, PrivilegesRequired, UserInteraction, Scope, Confidentiality, Integrity, Availability,
124
+ ExploitCodeMaturity, RemediationLevel, ReportConfidence,
125
+ ConfidentialityRequirement, IntegrityRequirement, AvailabilityRequirement,
126
+ ModifiedAttackVector, ModifiedAttackComplexity, ModifiedPrivilegesRequired, ModifiedUserInteraction, ModifiedScope,
127
+ ModifiedConfidentiality, ModifiedIntegrity, ModifiedAvailability) {
128
+
129
+ // If input validation fails, this array is populated with strings indicating which metrics failed validation.
130
+ var badMetrics = [];
131
+
132
+ // ENSURE ALL BASE METRICS ARE DEFINED
133
+ //
134
+ // We need values for all Base Score metrics to calculate scores.
135
+ // If any Base Score parameters are undefined, create an array of missing metrics and return it with an error.
136
+
137
+ if (typeof AttackVector === "undefined" || AttackVector === "") { badMetrics.push("AV"); }
138
+ if (typeof AttackComplexity === "undefined" || AttackComplexity === "") { badMetrics.push("AC"); }
139
+ if (typeof PrivilegesRequired === "undefined" || PrivilegesRequired === "") { badMetrics.push("PR"); }
140
+ if (typeof UserInteraction === "undefined" || UserInteraction === "") { badMetrics.push("UI"); }
141
+ if (typeof Scope === "undefined" || Scope === "") { badMetrics.push("S"); }
142
+ if (typeof Confidentiality === "undefined" || Confidentiality === "") { badMetrics.push("C"); }
143
+ if (typeof Integrity === "undefined" || Integrity === "") { badMetrics.push("I"); }
144
+ if (typeof Availability === "undefined" || Availability === "") { badMetrics.push("A"); }
145
+
146
+ if (badMetrics.length > 0) {
147
+ return { success: false, errorType: "MissingBaseMetric", errorMetrics: badMetrics };
148
+ }
149
+
150
+
151
+ // STORE THE METRIC VALUES THAT WERE PASSED AS PARAMETERS
152
+ //
153
+ // Temporal and Environmental metrics are optional, so set them to "X" ("Not Defined") if no value was passed.
154
+
155
+ var AV = AttackVector;
156
+ var AC = AttackComplexity;
157
+ var PR = PrivilegesRequired;
158
+ var UI = UserInteraction;
159
+ var S = Scope;
160
+ var C = Confidentiality;
161
+ var I = Integrity;
162
+ var A = Availability;
163
+
164
+ var E = ExploitCodeMaturity || "X";
165
+ var RL = RemediationLevel || "X";
166
+ var RC = ReportConfidence || "X";
167
+
168
+ var CR = ConfidentialityRequirement || "X";
169
+ var IR = IntegrityRequirement || "X";
170
+ var AR = AvailabilityRequirement || "X";
171
+ var MAV = ModifiedAttackVector || "X";
172
+ var MAC = ModifiedAttackComplexity || "X";
173
+ var MPR = ModifiedPrivilegesRequired || "X";
174
+ var MUI = ModifiedUserInteraction || "X";
175
+ var MS = ModifiedScope || "X";
176
+ var MC = ModifiedConfidentiality || "X";
177
+ var MI = ModifiedIntegrity || "X";
178
+ var MA = ModifiedAvailability || "X";
179
+
180
+
181
+ // CHECK VALIDITY OF METRIC VALUES
182
+ //
183
+ // Use the Weight object to ensure that, for every metric, the metric value passed is valid.
184
+ // If any invalid values are found, create an array of their metrics and return it with an error.
185
+ //
186
+ // The Privileges Required (PR) weight depends on Scope, but when checking the validity of PR we must not assume
187
+ // that the given value for Scope is valid. We therefore always look at the weights for Unchanged Scope when
188
+ // performing this check. The same applies for validation of Modified Privileges Required (MPR).
189
+ //
190
+ // The Weights object does not contain "X" ("Not Defined") values for Environmental metrics because we replace them
191
+ // with their Base metric equivalents later in the function. For example, an MAV of "X" will be replaced with the
192
+ // value given for AV. We therefore need to explicitly allow a value of "X" for Environmental metrics.
193
+
194
+ if (!CVSS.Weight.AV.hasOwnProperty(AV)) { badMetrics.push("AV"); }
195
+ if (!CVSS.Weight.AC.hasOwnProperty(AC)) { badMetrics.push("AC"); }
196
+ if (!CVSS.Weight.PR.U.hasOwnProperty(PR)) { badMetrics.push("PR"); }
197
+ if (!CVSS.Weight.UI.hasOwnProperty(UI)) { badMetrics.push("UI"); }
198
+ if (!CVSS.Weight.S.hasOwnProperty(S)) { badMetrics.push("S"); }
199
+ if (!CVSS.Weight.CIA.hasOwnProperty(C)) { badMetrics.push("C"); }
200
+ if (!CVSS.Weight.CIA.hasOwnProperty(I)) { badMetrics.push("I"); }
201
+ if (!CVSS.Weight.CIA.hasOwnProperty(A)) { badMetrics.push("A"); }
202
+
203
+ if (!CVSS.Weight.E.hasOwnProperty(E)) { badMetrics.push("E"); }
204
+ if (!CVSS.Weight.RL.hasOwnProperty(RL)) { badMetrics.push("RL"); }
205
+ if (!CVSS.Weight.RC.hasOwnProperty(RC)) { badMetrics.push("RC"); }
206
+
207
+ if (!(CR === "X" || CVSS.Weight.CIAR.hasOwnProperty(CR))) { badMetrics.push("CR"); }
208
+ if (!(IR === "X" || CVSS.Weight.CIAR.hasOwnProperty(IR))) { badMetrics.push("IR"); }
209
+ if (!(AR === "X" || CVSS.Weight.CIAR.hasOwnProperty(AR))) { badMetrics.push("AR"); }
210
+ if (!(MAV === "X" || CVSS.Weight.AV.hasOwnProperty(MAV))) { badMetrics.push("MAV"); }
211
+ if (!(MAC === "X" || CVSS.Weight.AC.hasOwnProperty(MAC))) { badMetrics.push("MAC"); }
212
+ if (!(MPR === "X" || CVSS.Weight.PR.U.hasOwnProperty(MPR))) { badMetrics.push("MPR"); }
213
+ if (!(MUI === "X" || CVSS.Weight.UI.hasOwnProperty(MUI))) { badMetrics.push("MUI"); }
214
+ if (!(MS === "X" || CVSS.Weight.S.hasOwnProperty(MS))) { badMetrics.push("MS"); }
215
+ if (!(MC === "X" || CVSS.Weight.CIA.hasOwnProperty(MC))) { badMetrics.push("MC"); }
216
+ if (!(MI === "X" || CVSS.Weight.CIA.hasOwnProperty(MI))) { badMetrics.push("MI"); }
217
+ if (!(MA === "X" || CVSS.Weight.CIA.hasOwnProperty(MA))) { badMetrics.push("MA"); }
218
+
219
+ if (badMetrics.length > 0) {
220
+ return { success: false, errorType: "UnknownMetricValue", errorMetrics: badMetrics };
221
+ }
222
+
223
+
224
+
225
+ // GATHER WEIGHTS FOR ALL METRICS
226
+
227
+ var metricWeightAV = CVSS.Weight.AV [AV];
228
+ var metricWeightAC = CVSS.Weight.AC [AC];
229
+ var metricWeightPR = CVSS.Weight.PR [S][PR]; // PR depends on the value of Scope (S).
230
+ var metricWeightUI = CVSS.Weight.UI [UI];
231
+ var metricWeightS = CVSS.Weight.S [S];
232
+ var metricWeightC = CVSS.Weight.CIA [C];
233
+ var metricWeightI = CVSS.Weight.CIA [I];
234
+ var metricWeightA = CVSS.Weight.CIA [A];
235
+
236
+ var metricWeightE = CVSS.Weight.E [E];
237
+ var metricWeightRL = CVSS.Weight.RL [RL];
238
+ var metricWeightRC = CVSS.Weight.RC [RC];
239
+
240
+ // For metrics that are modified versions of Base Score metrics, e.g. Modified Attack Vector, use the value of
241
+ // the Base Score metric if the modified version value is "X" ("Not Defined").
242
+ var metricWeightCR = CVSS.Weight.CIAR [CR];
243
+ var metricWeightIR = CVSS.Weight.CIAR [IR];
244
+ var metricWeightAR = CVSS.Weight.CIAR [AR];
245
+ var metricWeightMAV = CVSS.Weight.AV [MAV !== "X" ? MAV : AV];
246
+ var metricWeightMAC = CVSS.Weight.AC [MAC !== "X" ? MAC : AC];
247
+ var metricWeightMPR = CVSS.Weight.PR [MS !== "X" ? MS : S] [MPR !== "X" ? MPR : PR]; // Depends on MS.
248
+ var metricWeightMUI = CVSS.Weight.UI [MUI !== "X" ? MUI : UI];
249
+ var metricWeightMS = CVSS.Weight.S [MS !== "X" ? MS : S];
250
+ var metricWeightMC = CVSS.Weight.CIA [MC !== "X" ? MC : C];
251
+ var metricWeightMI = CVSS.Weight.CIA [MI !== "X" ? MI : I];
252
+ var metricWeightMA = CVSS.Weight.CIA [MA !== "X" ? MA : A];
253
+
254
+
255
+
256
+ // CALCULATE THE CVSS BASE SCORE
257
+
258
+ var baseScore;
259
+ var impactSubScore;
260
+ var exploitabalitySubScore = CVSS.exploitabilityCoefficient * metricWeightAV * metricWeightAC * metricWeightPR * metricWeightUI;
261
+ var impactSubScoreMultiplier = (1 - ((1 - metricWeightC) * (1 - metricWeightI) * (1 - metricWeightA)));
262
+
263
+ if (S === 'U') {
264
+ impactSubScore = metricWeightS * impactSubScoreMultiplier;
265
+ } else {
266
+ impactSubScore = metricWeightS * (impactSubScoreMultiplier - 0.029) - 3.25 * Math.pow(impactSubScoreMultiplier - 0.02, 15);
267
+ }
268
+
269
+ if (impactSubScore <= 0) {
270
+ baseScore = 0;
271
+ } else {
272
+ if (S === 'U') {
273
+ baseScore = CVSS.roundUp1(Math.min((exploitabalitySubScore + impactSubScore), 10));
274
+ } else {
275
+ baseScore = CVSS.roundUp1(Math.min((exploitabalitySubScore + impactSubScore) * CVSS.scopeCoefficient, 10));
276
+ }
277
+ }
278
+
279
+
280
+
281
+ // CALCULATE THE CVSS TEMPORAL SCORE
282
+
283
+ var temporalScore = CVSS.roundUp1(baseScore * metricWeightE * metricWeightRL * metricWeightRC);
284
+
285
+
286
+ // CALCULATE THE CVSS ENVIRONMENTAL SCORE
287
+ //
288
+ // - envExploitabalitySubScore recalculates the Base Score Exploitability sub-score using any modified values from the
289
+ // Environmental metrics group in place of the values specified in the Base Score, if any have been defined.
290
+ // - envAdjustedImpactSubScore recalculates the Base Score Impact sub-score using any modified values from the
291
+ // Environmental metrics group in place of the values specified in the Base Score, and any additional weightings
292
+ // given in the Environmental metrics group.
293
+
294
+ var envScore;
295
+ var envModifiedImpactSubScore;
296
+ var envModifiedExploitabalitySubScore = CVSS.exploitabilityCoefficient * metricWeightMAV * metricWeightMAC * metricWeightMPR * metricWeightMUI;
297
+
298
+ var envImpactSubScoreMultiplier = Math.min (1 - (
299
+ (1 - metricWeightMC * metricWeightCR) *
300
+ (1 - metricWeightMI * metricWeightIR) *
301
+ (1 - metricWeightMA * metricWeightAR)), 0.915);
302
+
303
+ if (MS === "U" ||
304
+ (MS === "X" && S === "U")) {
305
+ envModifiedImpactSubScore = metricWeightMS * envImpactSubScoreMultiplier;
306
+ envScore = CVSS.roundUp1(CVSS.roundUp1(Math.min(envModifiedImpactSubScore + envModifiedExploitabalitySubScore), 10) *
307
+ metricWeightE * metricWeightRL * metricWeightRC);
308
+ } else {
309
+ envModifiedImpactSubScore = metricWeightMS * (envImpactSubScoreMultiplier - 0.029) - 3.25 * Math.pow(envImpactSubScoreMultiplier - 0.02, 15);
310
+ envScore = CVSS.roundUp1(CVSS.roundUp1(Math.min(CVSS.scopeCoefficient * (envModifiedImpactSubScore + envModifiedExploitabalitySubScore), 10)) *
311
+ metricWeightE * metricWeightRL * metricWeightRC);
312
+ }
313
+
314
+ if (envModifiedImpactSubScore <= 0) {
315
+ envScore = 0;
316
+ }
317
+
318
+
319
+ // CONSTRUCT THE VECTOR STRING
320
+
321
+ var vectorString =
322
+ CVSS.CVSSVersionIdentifier +
323
+ "/AV:" + AV +
324
+ "/AC:" + AC +
325
+ "/PR:" + PR +
326
+ "/UI:" + UI +
327
+ "/S:" + S +
328
+ "/C:" + C +
329
+ "/I:" + I +
330
+ "/A:" + A;
331
+
332
+ if (E !== "X") {vectorString = vectorString + "/E:" + E;}
333
+ if (RL !== "X") {vectorString = vectorString + "/RL:" + RL;}
334
+ if (RC !== "X") {vectorString = vectorString + "/RC:" + RC;}
335
+
336
+ if (CR !== "X") {vectorString = vectorString + "/CR:" + CR;}
337
+ if (IR !== "X") {vectorString = vectorString + "/IR:" + IR;}
338
+ if (AR !== "X") {vectorString = vectorString + "/AR:" + AR;}
339
+ if (MAV !== "X") {vectorString = vectorString + "/MAV:" + MAV;}
340
+ if (MAC !== "X") {vectorString = vectorString + "/MAC:" + MAC;}
341
+ if (MPR !== "X") {vectorString = vectorString + "/MPR:" + MPR;}
342
+ if (MUI !== "X") {vectorString = vectorString + "/MUI:" + MUI;}
343
+ if (MS !== "X") {vectorString = vectorString + "/MS:" + MS;}
344
+ if (MC !== "X") {vectorString = vectorString + "/MC:" + MC;}
345
+ if (MI !== "X") {vectorString = vectorString + "/MI:" + MI;}
346
+ if (MA !== "X") {vectorString = vectorString + "/MA:" + MA;}
347
+
348
+
349
+ // Return an object containing the scores for all three metric groups, and an overall vector string.
350
+
351
+ return {
352
+ success: true,
353
+ baseMetricScore: baseScore.toFixed(1),
354
+ baseSeverity: CVSS.severityRating( baseScore.toFixed(1) ),
355
+
356
+ temporalMetricScore: temporalScore.toFixed(1),
357
+ temporalSeverity: CVSS.severityRating( temporalScore.toFixed(1) ),
358
+
359
+ environmentalMetricScore: envScore.toFixed(1),
360
+ environmentalSeverity: CVSS.severityRating( envScore.toFixed(1) ),
361
+
362
+ vectorString: vectorString
363
+ };
364
+ };
365
+
366
+
367
+
368
+
369
+ /* ** CVSS.calculateCVSSFromVector **
370
+ *
371
+ * Takes Base, Temporal and Environmental metric values as a single string in the Vector String format defined
372
+ * in the CVSS v3.0 standard definition of the Vector String.
373
+ *
374
+ * Returns Base, Temporal and Environmental scores, severity ratings, and an overall Vector String. All Base metrics
375
+ * are required to generate this output. All Temporal and Environmental metric values are optional. Any that are not
376
+ * passed default to "X" ("Not Defined").
377
+ *
378
+ * See the comment for the CVSS.calculateCVSSFromMetrics function for details on the function output. In addition to
379
+ * the error conditions listed for that function, this function can also return:
380
+ * "MalformedVectorString", if the Vector String passed is does not conform to the format in the standard; or
381
+ * "MultipleDefinitionsOfMetric", if the Vector String is well formed but defines the same metric (or metrics),
382
+ * more than once.
383
+ */
384
+ CVSS.calculateCVSSFromVector = function ( vectorString ) {
385
+
386
+ var metricValues = {
387
+ AV: undefined, AC: undefined, PR: undefined, UI: undefined, S: undefined,
388
+ C: undefined, I: undefined, A: undefined,
389
+ E: undefined, RL: undefined, RC: undefined,
390
+ CR: undefined, IR: undefined, AR: undefined,
391
+ MAV: undefined, MAC: undefined, MPR: undefined, MUI: undefined, MS: undefined,
392
+ MC: undefined, MI: undefined, MA: undefined
393
+ };
394
+
395
+ // If input validation fails, this array is populated with strings indicating which metrics failed validation.
396
+ var badMetrics = [];
397
+
398
+ if (!CVSS.vectorStringRegex_30.test(vectorString)) {
399
+ return { success: false, errorType: "MalformedVectorString" };
400
+ }
401
+
402
+ var metricNameValue = vectorString.substring(CVSS.CVSSVersionIdentifier.length).split("/");
403
+
404
+ for (var i in metricNameValue) {
405
+ if (metricNameValue.hasOwnProperty(i)) {
406
+
407
+ var singleMetric = metricNameValue[i].split(":");
408
+
409
+ if (typeof metricValues[singleMetric[0]] === "undefined") {
410
+ metricValues[singleMetric[0]] = singleMetric[1];
411
+ } else {
412
+ badMetrics.push(singleMetric[0]);
413
+ }
414
+ }
415
+ }
416
+
417
+ if (badMetrics.length > 0) {
418
+ return { success: false, errorType: "MultipleDefinitionsOfMetric", errorMetrics: badMetrics };
419
+ }
420
+
421
+ return CVSS.calculateCVSSFromMetrics (
422
+ metricValues.AV, metricValues.AC, metricValues.PR, metricValues.UI, metricValues.S,
423
+ metricValues.C, metricValues.I, metricValues.A,
424
+ metricValues.E, metricValues.RL, metricValues.RC,
425
+ metricValues.CR, metricValues.IR, metricValues.AR,
426
+ metricValues.MAV, metricValues.MAC, metricValues.MPR, metricValues.MUI, metricValues.MS,
427
+ metricValues.MC, metricValues.MI, metricValues.MA);
428
+ };
429
+
430
+
431
+
432
+
433
+ /* ** CVSS.roundUp1 **
434
+ *
435
+ * Rounds up the number passed as a parameter to 1 decimal place and returns the result.
436
+ *
437
+ * Standard JavaScript errors thrown when arithmetic operations are performed on non-numbers will be returned if the
438
+ * given input is not a number.
439
+ */
440
+ CVSS.roundUp1 = function (d) {
441
+ return Math.ceil (d * 10) / 10;
442
+ };
443
+
444
+
445
+
446
+
447
+ /* ** CVSS.severityRating **
448
+ *
449
+ * Given a CVSS score, returns the name of the severity rating as defined in the CVSS standard.
450
+ * The input needs to be a number between 0.0 to 10.0, to one decimal place of precision.
451
+ *
452
+ * The following error values may be returned instead of a severity rating name:
453
+ * NaN (JavaScript "Not a Number") - if the input is not a number.
454
+ * undefined - if the input is a number that is not within the range of any defined severity rating.
455
+ */
456
+ CVSS.severityRating = function (score) {
457
+ var severityRatingLength = CVSS.severityRatings.length;
458
+
459
+ var validatedScore = Number(score);
460
+
461
+ if (isNaN(validatedScore)) {
462
+ return validatedScore;
463
+ }
464
+
465
+ for (var i = 0; i < severityRatingLength; i++) {
466
+ if (score >= CVSS.severityRatings[i].bottom && score <= CVSS.severityRatings[i].top) {
467
+ return CVSS.severityRatings[i].name;
468
+ }
469
+ }
470
+
471
+ return undefined;
472
+ };
473
+
474
+
475
+
476
+ ///////////////////////////////////////////////////////////////////////////
477
+ // DATA AND FUNCTIONS FOR CREATING AN XML REPRESENTATION OF A CVSS SCORE //
478
+ ///////////////////////////////////////////////////////////////////////////
479
+
480
+ // A mapping between abbreviated metric values and the string used in the XML representation.
481
+ // For example, a Remediation Level (RL) abbreviated metric value of "W" maps to "WORKAROUND".
482
+ // For brevity, Base metric values their modified equivalents in the Environmental metric group. We can do this
483
+ // because the latter is the same as the former, except it also includes a "NOT_DEFINED" value.
484
+
485
+ CVSS.XML_MetricNames = {
486
+ E: { X: "NOT_DEFINED", U: "UNPROVEN", P: "PROOF_OF_CONCEPT", F: "FUNCTIONAL", H: "HIGH"},
487
+ RL: { X: "NOT_DEFINED", O: "OFFICIAL_FIX", T: "TEMPORARY_FIX", W: "WORKAROUND", U: "UNAVAILABLE"},
488
+ RC: { X: "NOT_DEFINED", U: "UNKNOWN", R: "REASONABLE", C: "CONFIRMED"},
489
+
490
+ CIAR: { X: "NOT_DEFINED", L: "LOW", M: "MEDIUM", H: "HIGH"}, // CR, IR and AR use the same metric names
491
+ MAV: { N: "NETWORK", A: "ADJACENT_NETWORK", L: "LOCAL", P: "PHYSICAL", X: "NOT_DEFINED" },
492
+ MAC: { H: "HIGH", L: "LOW", X: "NOT_DEFINED" },
493
+ MPR: { N: "NONE", L: "LOW", H: "HIGH", X: "NOT_DEFINED" },
494
+ MUI: { N: "NONE", R: "REQUIRED", X: "NOT_DEFINED" },
495
+ MS: { U: "UNCHANGED", C: "CHANGED", X: "NOT_DEFINED" },
496
+ MCIA: { N: "NONE", L: "LOW", H: "HIGH", X: "NOT_DEFINED" } // C, I and A use the same metric names
497
+ };
498
+
499
+
500
+
501
+ /* ** CVSS.generateXMLFromMetrics **
502
+ *
503
+ * Takes Base, Temporal and Environmental metric values as individual parameters. Their values are in the short format
504
+ * defined in the CVSS v3.0 standard definition of the Vector String. For example, the AttackComplexity parameter
505
+ * should be either "H" or "L".
506
+ *
507
+ * Returns a single string containing the metric values in XML form. All Base metrics are required to generate this
508
+ * output. All Temporal and Environmental metric values are optional. Any that are not passed will be represented in
509
+ * the XML as NOT_DEFINED. The function returns a string for simplicity. It is arguably better to return the XML as
510
+ * a DOM object, but at the time of writing this leads to complexity due to older browsers using different JavaScript
511
+ * interfaces to do this. Also for simplicity, all Temporal and Environmental metrics are include in the string,
512
+ * even though those with a value of "Not Defined" do not need to be included.
513
+ *
514
+ * The output of this function is an object which always has a property named "success".
515
+ *
516
+ * If no errors are encountered, success is Boolean "true", and the "xmlString" property contains the XML string
517
+ * representation.
518
+ *
519
+ * If errors are encountered, success is Boolean "false", and other properties are defined as per the
520
+ * CVSS.calculateCVSSFromMetrics function. Refer to the comment for that function for more details.
521
+ */
522
+ CVSS.generateXMLFromMetrics = function (
523
+ AttackVector, AttackComplexity, PrivilegesRequired, UserInteraction, Scope, Confidentiality, Integrity, Availability,
524
+ ExploitCodeMaturity, RemediationLevel, ReportConfidence,
525
+ ConfidentialityRequirement, IntegrityRequirement, AvailabilityRequirement,
526
+ ModifiedAttackVector, ModifiedAttackComplexity, ModifiedPrivilegesRequired, ModifiedUserInteraction, ModifiedScope,
527
+ ModifiedConfidentiality, ModifiedIntegrity, ModifiedAvailability) {
528
+
529
+ // A string containing the XML we wish to output, with placeholders for the CVSS metrics we will substitute for
530
+ // their values, based on the inputs passed to this function.
531
+ var xmlTemplate =
532
+ '<?xml version="1.0" encoding="UTF-8"?>\n' +
533
+ '<cvssv3.0 xmlns="https://www.first.org/cvss/cvss-v3.0.xsd"\n' +
534
+ ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' +
535
+ ' xsi:schemaLocation="https://www.first.org/cvss/cvss-v3.0.xsd https://www.first.org/cvss/cvss-v3.0.xsd"\n' +
536
+ ' >\n' +
537
+ '\n' +
538
+ ' <base_metrics>\n' +
539
+ ' <attack-vector>__AttackVector__</attack-vector>\n' +
540
+ ' <attack-complexity>__AttackComplexity__</attack-complexity>\n' +
541
+ ' <privileges-required>__PrivilegesRequired__</privileges-required>\n' +
542
+ ' <user-interaction>__UserInteraction__</user-interaction>\n' +
543
+ ' <scope>__Scope__</scope>\n' +
544
+ ' <confidentiality-impact>__Confidentiality__</confidentiality-impact>\n' +
545
+ ' <integrity-impact>__Integrity__</integrity-impact>\n' +
546
+ ' <availability-impact>__Availability__</availability-impact>\n' +
547
+ ' <base-score>__BaseScore__</base-score>\n' +
548
+ ' <base-severity>__BaseSeverityRating__</base-severity>\n' +
549
+ ' </base_metrics>\n' +
550
+ '\n' +
551
+ ' <temporal_metrics>\n' +
552
+ ' <exploit-code-maturity>__ExploitCodeMaturity__</exploit-code-maturity>\n' +
553
+ ' <remediation-level>__RemediationLevel__</remediation-level>\n' +
554
+ ' <report-confidence>__ReportConfidence__</report-confidence>\n' +
555
+ ' <temporal-score>__TemporalScore__</temporal-score>\n' +
556
+ ' <temporal-severity>__TemporalSeverityRating__</temporal-severity>\n' +
557
+ ' </temporal_metrics>\n' +
558
+ '\n' +
559
+ ' <environmental_metrics>\n' +
560
+ ' <confidentiality-requirement>__ConfidentialityRequirement__</confidentiality-requirement>\n' +
561
+ ' <integrity-requirement>__IntegrityRequirement__</integrity-requirement>\n' +
562
+ ' <availability-requirement>__AvailabilityRequirement__</availability-requirement>\n' +
563
+ ' <modified-attack-vector>__ModifiedAttackVector__</modified-attack-vector>\n' +
564
+ ' <modified-attack-complexity>__ModifiedAttackComplexity__</modified-attack-complexity>\n' +
565
+ ' <modified-privileges-required>__ModifiedPrivilegesRequired__</modified-privileges-required>\n' +
566
+ ' <modified-user-interaction>__ModifiedUserInteraction__</modified-user-interaction>\n' +
567
+ ' <modified-scope>__ModifiedScope__</modified-scope>\n' +
568
+ ' <modified-confidentiality-impact>__ModifiedConfidentiality__</modified-confidentiality-impact>\n' +
569
+ ' <modified-integrity-impact>__ModifiedIntegrity__</modified-integrity-impact>\n' +
570
+ ' <modified-availability-impact>__ModifiedAvailability__</modified-availability-impact>\n' +
571
+ ' <environmental-score>__EnvironmentalScore__</environmental-score>\n' +
572
+ ' <environmental-severity>__EnvironmentalSeverityRating__</environmental-severity>\n' +
573
+ ' </environmental_metrics>\n' +
574
+ '\n' +
575
+ '</cvssv3.0>\n';
576
+
577
+
578
+ // Call CVSS.calculateCVSSFromMetrics to validate all the parameters and generate scores and severity ratings.
579
+ // If that function returns an error, immediately return it to the caller of this function.
580
+ var result = CVSS.calculateCVSSFromMetrics (
581
+ AttackVector, AttackComplexity, PrivilegesRequired, UserInteraction, Scope, Confidentiality, Integrity, Availability,
582
+ ExploitCodeMaturity, RemediationLevel, ReportConfidence,
583
+ ConfidentialityRequirement, IntegrityRequirement, AvailabilityRequirement,
584
+ ModifiedAttackVector, ModifiedAttackComplexity, ModifiedPrivilegesRequired, ModifiedUserInteraction, ModifiedScope,
585
+ ModifiedConfidentiality, ModifiedIntegrity, ModifiedAvailability);
586
+
587
+ if (result.success !== true) {
588
+ return result;
589
+ }
590
+
591
+ var xmlOutput = xmlTemplate;
592
+ xmlOutput = xmlOutput.replace ("__AttackVector__", CVSS.XML_MetricNames["MAV"][AttackVector]);
593
+ xmlOutput = xmlOutput.replace ("__AttackComplexity__", CVSS.XML_MetricNames["MAC"][AttackComplexity]);
594
+ xmlOutput = xmlOutput.replace ("__PrivilegesRequired__", CVSS.XML_MetricNames["MPR"][PrivilegesRequired]);
595
+ xmlOutput = xmlOutput.replace ("__UserInteraction__", CVSS.XML_MetricNames["MUI"][UserInteraction]);
596
+ xmlOutput = xmlOutput.replace ("__Scope__", CVSS.XML_MetricNames["MS"][Scope]);
597
+ xmlOutput = xmlOutput.replace ("__Confidentiality__", CVSS.XML_MetricNames["MCIA"][Confidentiality]);
598
+ xmlOutput = xmlOutput.replace ("__Integrity__", CVSS.XML_MetricNames["MCIA"][Integrity]);
599
+ xmlOutput = xmlOutput.replace ("__Availability__", CVSS.XML_MetricNames["MCIA"][Availability]);
600
+ xmlOutput = xmlOutput.replace ("__BaseScore__", result.baseMetricScore);
601
+ xmlOutput = xmlOutput.replace ("__BaseSeverityRating__", result.baseSeverity);
602
+
603
+ xmlOutput = xmlOutput.replace ("__ExploitCodeMaturity__", CVSS.XML_MetricNames["E"][ExploitCodeMaturity || "X"]);
604
+ xmlOutput = xmlOutput.replace ("__RemediationLevel__", CVSS.XML_MetricNames["RL"][RemediationLevel || "X"]);
605
+ xmlOutput = xmlOutput.replace ("__ReportConfidence__", CVSS.XML_MetricNames["RC"][ReportConfidence || "X"]);
606
+ xmlOutput = xmlOutput.replace ("__TemporalScore__", result.temporalMetricScore);
607
+ xmlOutput = xmlOutput.replace ("__TemporalSeverityRating__", result.temporalSeverity);
608
+
609
+ xmlOutput = xmlOutput.replace ("__ConfidentialityRequirement__", CVSS.XML_MetricNames["CIAR"][ConfidentialityRequirement || "X"]);
610
+ xmlOutput = xmlOutput.replace ("__IntegrityRequirement__", CVSS.XML_MetricNames["CIAR"][IntegrityRequirement || "X"]);
611
+ xmlOutput = xmlOutput.replace ("__AvailabilityRequirement__", CVSS.XML_MetricNames["CIAR"][AvailabilityRequirement || "X"]);
612
+ xmlOutput = xmlOutput.replace ("__ModifiedAttackVector__", CVSS.XML_MetricNames["MAV"][ModifiedAttackVector || "X"]);
613
+ xmlOutput = xmlOutput.replace ("__ModifiedAttackComplexity__", CVSS.XML_MetricNames["MAC"][ModifiedAttackComplexity || "X"]);
614
+ xmlOutput = xmlOutput.replace ("__ModifiedPrivilegesRequired__", CVSS.XML_MetricNames["MPR"][ModifiedPrivilegesRequired || "X"]);
615
+ xmlOutput = xmlOutput.replace ("__ModifiedUserInteraction__", CVSS.XML_MetricNames["MUI"][ModifiedUserInteraction || "X"]);
616
+ xmlOutput = xmlOutput.replace ("__ModifiedScope__", CVSS.XML_MetricNames["MS"][ModifiedScope || "X"]);
617
+ xmlOutput = xmlOutput.replace ("__ModifiedConfidentiality__", CVSS.XML_MetricNames["MCIA"][ModifiedConfidentiality || "X"]);
618
+ xmlOutput = xmlOutput.replace ("__ModifiedIntegrity__", CVSS.XML_MetricNames["MCIA"][ModifiedIntegrity || "X"]);
619
+ xmlOutput = xmlOutput.replace ("__ModifiedAvailability__", CVSS.XML_MetricNames["MCIA"][ModifiedAvailability || "X"]);
620
+ xmlOutput = xmlOutput.replace ("__EnvironmentalScore__", result.environmentalMetricScore);
621
+ xmlOutput = xmlOutput.replace ("__EnvironmentalSeverityRating__", result.environmentalSeverity);
622
+
623
+ return { success: true, xmlString: xmlOutput };
624
+ };
625
+
626
+
627
+
628
+ /* ** CVSS.generateXMLFromVector **
629
+ *
630
+ * Takes Base, Temporal and Environmental metric values as a single string in the Vector String format defined
631
+ * in the CVSS v3.0 standard definition of the Vector String.
632
+ *
633
+ * Returns an XML string representation of this input. See the comment for CVSS.generateXMLFromMetrics for more
634
+ * detail on inputs, return values and errors. In addition to the error conditions listed for that function, this
635
+ * function can also return:
636
+ * "MalformedVectorString", if the Vector String passed is does not conform to the format in the standard; or
637
+ * "MultipleDefinitionsOfMetric", if the Vector String is well formed but defines the same metric (or metrics),
638
+ * more than once.
639
+ */
640
+ CVSS.generateXMLFromVector = function ( vectorString ) {
641
+
642
+ var metricValues = {
643
+ AV: undefined, AC: undefined, PR: undefined, UI: undefined, S: undefined,
644
+ C: undefined, I: undefined, A: undefined,
645
+ E: undefined, RL: undefined, RC: undefined,
646
+ CR: undefined, IR: undefined, AR: undefined,
647
+ MAV: undefined, MAC: undefined, MPR: undefined, MUI: undefined, MS: undefined,
648
+ MC: undefined, MI: undefined, MA: undefined
649
+ };
650
+
651
+ // If input validation fails, this array is populated with strings indicating which metrics failed validation.
652
+ var badMetrics = [];
653
+
654
+ if (!CVSS.vectorStringRegex_30.test(vectorString)) {
655
+ return { success: false, errorType: "MalformedVectorString" };
656
+ }
657
+
658
+ var metricNameValue = vectorString.substring(CVSS.CVSSVersionIdentifier.length).split("/");
659
+
660
+ for (var i in metricNameValue) {
661
+ if (metricNameValue.hasOwnProperty(i)) {
662
+
663
+ var singleMetric = metricNameValue[i].split(":");
664
+
665
+ if (typeof metricValues[singleMetric[0]] === "undefined") {
666
+ metricValues[singleMetric[0]] = singleMetric[1];
667
+ } else {
668
+ badMetrics.push(singleMetric[0]);
669
+ }
670
+ }
671
+ }
672
+
673
+ if (badMetrics.length > 0) {
674
+ return { success: false, errorType: "MultipleDefinitionsOfMetric", errorMetrics: badMetrics };
675
+ }
676
+
677
+ return CVSS.generateXMLFromMetrics (
678
+ metricValues.AV, metricValues.AC, metricValues.PR, metricValues.UI, metricValues.S,
679
+ metricValues.C, metricValues.I, metricValues.A,
680
+ metricValues.E, metricValues.RL, metricValues.RC,
681
+ metricValues.CR, metricValues.IR, metricValues.AR,
682
+ metricValues.MAV, metricValues.MAC, metricValues.MPR, metricValues.MUI, metricValues.MS,
683
+ metricValues.MC, metricValues.MI, metricValues.MA);
684
+ };