diff options
Diffstat (limited to 'cvss/v2vector.go')
-rw-r--r-- | cvss/v2vector.go | 228 |
1 files changed, 225 insertions, 3 deletions
diff --git a/cvss/v2vector.go b/cvss/v2vector.go index e015544..f4c26e2 100644 --- a/cvss/v2vector.go +++ b/cvss/v2vector.go @@ -2,6 +2,7 @@ package cvss import ( // "encoding/json" + "math" "regexp" "strings" ) @@ -43,7 +44,228 @@ func (v v2Vector) Metrics() []Metric { // Return numerical scores for this vector. func (v v2Vector) Scores() (Scores, error) { - return newScoresFromV2Vector(v) + // 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 NewScores(baseScore, tempScore, envScore) } // Create CVSS 2.0 vector from string. @@ -74,14 +296,14 @@ func newV2Vector(s string) (v2Vector, error) { // if err := json.Unmarshal(b, &s); err != nil { // return err // } -// +// // // parse vector, check for error // r, err := newV2Vector(s) // if err != nil { // // return error // return err // } -// +// // // save result, return success // *me = r // return nil |