1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
package cvss
import (
"math"
)
// CVSS v2 base, temporal, and environmental scores.
type v2Scores struct {
base v2Score // base score
temporal v2Score // temporal score
env v2Score // environmental score
}
// Create new CVSS v2Scores from floats.
func newV2ScoresFromFloats(base, temporal, env float64) (v2Scores, error) {
// convert base score from float to v2score
baseScore, err := newV2Score(base)
if err != nil {
return v2Scores{}, err
}
// convert temporal score from float to v2score
tempScore, err := newV2Score(temporal)
if err != nil {
return v2Scores{}, err
}
// convert env score from float to v2score
envScore, err := newV2Score(env)
if err != nil {
return v2Scores{}, err
}
// return success
return v2Scores {
base: baseScore,
temporal: tempScore,
env: envScore,
}, nil
}
// Create new v2 scores from v2 vector.
func newV2Scores(v v2Vector) (v2Scores, error) {
// CVSS v2 (https://www.first.org/cvss/v2/guide 3.2.1)
//
// Impact = 10.41*(1-(1-ConfImpact)*(1-IntegImpact)*(1-AvailImpact))
// Exploitability = 20* AccessVector*AccessComplexity*Authentication
// f(impact)= 0 if Impact=0, 1.176 otherwise
// BaseScore = round_to_1_decimal(((0.6*Impact)+(0.4*Exploitability)-1.5)*f(Impact))
// base score values
confImpact := 0.0
integImpact := 0.0
availImpact := 0.0
accessVector := 0.0
accessComplexity := 0.0
auth := 0.0
// temporal score values
// (FIXME: should these be set to 1.0?)
exploitability := 0.0
remediationLevel := 0.0
reportConfidence := 0.0
// env score values
cdp := 0.0
td := 0.0
confReq := 0.0
integReq := 0.0
availReq := 0.0
for _, m := range([]v2Metric(v)) {
switch m {
case v2AVNetwork: // AV:N
accessVector = 1.0
case v2AVAdjacentNetwork: // AV:A
accessVector = 0.646
case v2AVLocal: // AV:L
accessVector = 0.395
case v2ACLow: // AC:L
accessComplexity = 0.71
case v2ACMedium: // AC:M
accessComplexity = 0.61
case v2ACHigh: // AC:H
accessComplexity = 0.35
case v2AuMultiple: // Au:M
auth = 0.45
case v2AuSingle: // Au:S
auth = 0.56
case v2AuNone: // Au:N
auth = 0.704
case v2CNone: // C:N
confImpact = 0.0
case v2CPartial: // C:P
confImpact = 0.275
case v2CComplete: // C:C
confImpact = 0.660
case v2INone: // I:N
integImpact = 0.0
case v2IPartial: // I:P
integImpact = 0.275
case v2IComplete: // I:C
integImpact = 0.660
case v2ANone: // A:N
availImpact = 0.0
case v2APartial: // A:P
availImpact = 0.275
case v2AComplete: // A:C
availImpact = 0.660
case v2ENotDefined: // E:ND
exploitability = 1.0
case v2EUnproven: // E:U
exploitability = 0.85
case v2EProofOfConcept: // E:POC
exploitability = 0.9
case v2EFunctional: // E:F
exploitability = 0.95
case v2EHigh: // E:H
exploitability = 1.0
case v2RLOfficialFix: // RL:OF
remediationLevel = 0.87
case v2RLTemporaryFix: // RL:TF
remediationLevel = 0.9
case v2RLWorkaround: // RL:W
remediationLevel = 0.95
case v2RLUnavailable: // RL:U
remediationLevel = 1.0
case v2RLNotDefined: // RL:ND
remediationLevel = 1.0
case v2RCUnconfirmed: // RC:UC
reportConfidence = 0.9
case v2RCUncorroborated: // RC:UR
reportConfidence = 0.95
case v2RCConfirmed: // RC:C
reportConfidence = 1.0
case v2RCNotDefined: // RC:ND
reportConfidence = 1.0
case v2CDPNone: // CDP:N
cdp = 0.0
case v2CDPLow: // CDP:L
cdp = 0.1
case v2CDPLowMedium: // CDP:LM
cdp = 0.3
case v2CDPMediumHigh: // CDP:MH
cdp = 0.4
case v2CDPHigh: // CDP:H
cdp = 0.5
case v2CDPNotDefined: // CDP:ND
cdp = 0.0
case v2TDNone: // TD:N
td = 0.0
case v2TDLow: // TD:L
td = 0.25
case v2TDMedium: // TD:M
td = 0.75
case v2TDHigh: // TD:H
td = 1.0
case v2TDNotDefined: // TD:ND
td = 1.0
case v2CRLow: // CR:L
confReq = 0.5
case v2CRMedium: // CR:M
confReq = 1.0
case v2CRHigh: // CR:H
confReq = 1.51
case v2CRNotDefined: // CR:ND
confReq = 1.0
case v2IRLow: // IR:L
integReq = 0.5
case v2IRMedium: // IR:M
integReq = 1.0
case v2IRHigh: // IR:H
integReq = 1.51
case v2IRNotDefined: // IR:ND
integReq = 1.0
case v2ARLow: // AR:L
availReq = 0.5
case v2ARMedium: // AR:M
availReq = 1.0
case v2ARHigh: // AR:H
availReq = 1.51
case v2ARNotDefined: // AR:ND
availReq = 1.0
}
}
// calculate base score (3.2.1 Base Equation)
//
// Impact = 10.41*(1-(1-ConfImpact)*(1-IntegImpact)*(1-AvailImpact))
// Exploitability = 20* AccessVector*AccessComplexity*Authentication
// f(impact)= 0 if Impact=0, 1.176 otherwise
// BaseScore = round_to_1_decimal(((0.6*Impact)+(0.4*Exploitability)-1.5)*f(Impact))
baseScore := 0.0
{
impact := 10.41 * (1 - (1 - confImpact) * (1 - integImpact) * (1 - availImpact))
fImpact := 0.0
if impact > 0.0 {
fImpact = 1.176
}
baseExpl := 20 * accessVector * accessComplexity * auth
baseScore = ((0.6 * impact + 0.4 * baseExpl) - 1.5) * fImpact
baseScore = math.Round(10.0 * baseScore) / 10.0
}
// calculate temporal score (3.2.2 Temporal Equation)
//
// TemporalScore = round_to_1_decimal(BaseScore*Exploitability
// *RemediationLevel*ReportConfidence)
tempScore := 0.0
{
tempScore = baseScore * exploitability * remediationLevel * reportConfidence
tempScore = math.Round(10.0 * tempScore) / 10.0
}
// calculate environmental score (3.2.3 Environmental Equation)
//
// AdjustedImpact = min(10,10.41*(1-(1-ConfImpact*ConfReq)*(1-IntegImpact*IntegReq)
// *(1-AvailImpact*AvailReq)))
//
// AdjustedTemporal = TemporalScore recomputed with the BaseScore's
// Impact sub-equation replaced with the AdjustedImpact equation
//
// EnvironmentalScore = round_to_1_decimal((AdjustedTemporal+
// (10-AdjustedTemporal)*CollateralDamagePotential)*TargetDistribution)
//
envScore := 0.0
{
// calc adjusted impact
adjImpact := math.Min(
10.0,
10.41 * (1 - (1 - confImpact * confReq) * (1 - integImpact * integReq) * (1 - availImpact * availReq)),
)
fImpact := 0.0
if adjImpact > 0.0 {
fImpact = 1.176
}
// calculate environmental base score using adjusted impact
baseExpl := 20 * accessVector * accessComplexity * auth
envBaseScore := ((0.6 * adjImpact + 0.4 * baseExpl) - 1.5) * fImpact
envBaseScore = (10.0 * envBaseScore) / 10.0
// calculate adjusted temporal score
adjTempScore := envBaseScore * exploitability * remediationLevel * reportConfidence
adjTempScore = math.Round(10.0 * adjTempScore) / 10.0
envScore = (adjTempScore + (10 - adjTempScore) * cdp) * td
envScore = math.Round(10.0 * envScore) / 10.0
}
// build and return result
return newV2ScoresFromFloats(baseScore, tempScore, envScore)
}
|