package cvss import ( "math" ) // CVSS score set. type Scores struct { Base Score `json:"base"` // base score Temporal Score `json:"temporal"` // temporal score Env Score `json:"env"` // environmental score } // Create new score set from floats. func NewScores(base, temporal, env float64) (Scores, error) { // convert base from float to Score baseScore, err := NewScore(base) if err != nil { return Scores{}, err } // convert temporal from float to Score tempScore, err := NewScore(temporal) if err != nil { return Scores{}, err } // convert env from float to Score envScore, err := NewScore(env) if err != nil { return Scores{}, err } // return success return Scores { Base: baseScore, Temporal: tempScore, Env: envScore, }, nil } // Create new v2 scores from v2 vector. func newScoresFromV2Vector(v v2Vector) (Scores, 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 NewScores(baseScore, tempScore, envScore) }