From 0e03944172f24e2a05bce8a0214f06442d356343 Mon Sep 17 00:00:00 2001 From: unorsk <25188+unorsk@users.noreply.github.com> Date: Wed, 12 Jun 2024 21:39:54 +0200 Subject: [PATCH 1/6] Updating tests to run as separate test cases, instead of just one test case --- code/cvss/src/Security/CVSS.hs | 13 +++++++++++++ code/cvss/test/Spec.hs | 34 ++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/code/cvss/src/Security/CVSS.hs b/code/cvss/src/Security/CVSS.hs index e47654dc..5c640a96 100644 --- a/code/cvss/src/Security/CVSS.hs +++ b/code/cvss/src/Security/CVSS.hs @@ -189,6 +189,19 @@ data MetricValue = MetricValue mvDesc :: Text } +cvss40 :: CVSSDB +cvss40 = + CVSSDB + [ MetricGroup "Base" baseMetrics, + MetricGroup "Temporal" temporalMetrics, + MetricGroup "Environmental" environmentalMetrics + ] + where + baseMetrics = [] + temporalMetrics = [] + environmentalMetrics = [] + + -- | CVSS3.1 metrics pulled from section 2. "Base Metrics" and section section 7.4. "Metric Values" cvss31 :: CVSSDB cvss31 = diff --git a/code/cvss/test/Spec.hs b/code/cvss/test/Spec.hs index 5faccf73..6e092da3 100644 --- a/code/cvss/test/Spec.hs +++ b/code/cvss/test/Spec.hs @@ -2,26 +2,28 @@ module Main where -import Control.Monad -import Data.Text (Text) +import Data.Text (Text, unpack) import qualified Security.CVSS as CVSS import Test.Tasty import Test.Tasty.HUnit main :: IO () main = defaultMain $ - testCase "Security.CVSS" $ do - forM_ examples $ \(cvssString, score, rating) -> do - case CVSS.parseCVSS cvssString of - Left e -> assertFailure (show e) - Right cvss -> do - CVSS.cvssScore cvss @?= (rating, score) - CVSS.cvssVectorString cvss @?= cvssString - CVSS.cvssVectorStringOrdered cvss @?= cvssString + testGroup "Security.CVSS" $ + map runTest testCases where + runTest (cvssString, score, rating) = testCase (unpack cvssString) $ + case CVSS.parseCVSS cvssString of + Left e -> assertFailure (show e) + Right cvss -> do + CVSS.cvssScore cvss @?= (rating, score) + CVSS.cvssVectorString cvss @?= cvssString + CVSS.cvssVectorStringOrdered cvss @?= cvssString -examples :: [(Text, Float, CVSS.Rating)] -examples = - [ ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N", 5.8, CVSS.Medium) +testCases :: [(Text, Float, CVSS.Rating)] +testCases = + [--("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/S:P/AU:Y/V:C/RE:L", 9.4, CVSS.Critical) + ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 8.8, CVSS.High) + , ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N", 5.8, CVSS.Medium) , ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N", 6.4, CVSS.Medium) , ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.1, CVSS.Low) , ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", 6.1, CVSS.Medium) @@ -30,7 +32,7 @@ examples = , ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 4.0, CVSS.Medium) , ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", 9.9, CVSS.Critical) , ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L", 4.2, CVSS.Medium) - , ("CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:C", 7.8, CVSS.High) - , ("CVSS:2.0/AV:N/AC:L/Au:N/C:C/I:C/A:C", 10, CVSS.Critical) - , ("CVSS:2.0/AV:L/AC:H/Au:N/C:C/I:C/A:C", 6.2, CVSS.Medium) + , ("CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:C", 7.8, CVSS.High) + , ("CVSS:2.0/AV:N/AC:L/Au:N/C:C/I:C/A:C", 10, CVSS.Critical) + , ("CVSS:2.0/AV:L/AC:H/Au:N/C:C/I:C/A:C", 6.2, CVSS.Medium) ] From cf61ecf5e47baf72c554e44a2961498c9d3d8bf9 Mon Sep 17 00:00:00 2001 From: unorsk <25188+unorsk@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:32:03 +0200 Subject: [PATCH 2/6] Enumerating all possible metrics for CVSS4.0 --- code/cvss/src/Security/CVSS.hs | 271 ++++++++++++++++++++++++++++++++- code/cvss/test/Spec.hs | 58 ++++--- 2 files changed, 304 insertions(+), 25 deletions(-) diff --git a/code/cvss/src/Security/CVSS.hs b/code/cvss/src/Security/CVSS.hs index 5c640a96..fa0cae21 100644 --- a/code/cvss/src/Security/CVSS.hs +++ b/code/cvss/src/Security/CVSS.hs @@ -36,7 +36,9 @@ import GHC.Float (powerFloat) -- | The CVSS version. data CVSSVersion - = -- | Version 3.1: https://www.first.org/cvss/v3-1/ + = -- | Version 4.0: https://www.first.org/cvss/v4.0/ + CVSS40 + | -- | Version 3.1: https://www.first.org/cvss/v3-1/ CVSS31 | -- | Version 3.0: https://www.first.org/cvss/v3.0/ CVSS30 @@ -107,6 +109,7 @@ data Metric = Metric -- | Parse a CVSS string. parseCVSS :: Text -> Either CVSSError CVSS parseCVSS txt + | "CVSS:4.0/" `Text.isPrefixOf` txt = CVSS CVSS40 <$> validateComponents validateCvss40 | "CVSS:3.1/" `Text.isPrefixOf` txt = CVSS CVSS31 <$> validateComponents validateCvss31 | "CVSS:3.0/" `Text.isPrefixOf` txt = CVSS CVSS30 <$> validateComponents validateCvss30 | "CVSS:2.0/" `Text.isPrefixOf` txt = CVSS CVSS20 <$> validateComponents validateCvss20 @@ -127,6 +130,7 @@ parseCVSS txt -- | Compute the base score. cvssScore :: CVSS -> (Rating, Float) cvssScore cvss = case cvssVersion cvss of + CVSS40 -> cvss40score (cvssMetrics cvss) CVSS31 -> cvss31score (cvssMetrics cvss) CVSS30 -> cvss30score (cvssMetrics cvss) CVSS20 -> cvss20score (cvssMetrics cvss) @@ -145,6 +149,7 @@ cvssVectorStringOrdered = cvssShow True cvssShow :: Bool -> CVSS -> Text cvssShow ordered cvss = case cvssVersion cvss of + CVSS40 -> Text.intercalate "/" ("CVSS:4.0" : components) CVSS31 -> Text.intercalate "/" ("CVSS:3.1" : components) CVSS30 -> Text.intercalate "/" ("CVSS:3.0" : components) CVSS20 -> Text.intercalate "/" ("CVSS:2.0" : components) @@ -162,6 +167,7 @@ newtype CVSSDB = CVSSDB [MetricGroup] cvssDB :: CVSSVersion -> CVSSDB cvssDB v = case v of + CVSS40 -> cvss40 CVSS31 -> cvss31 CVSS30 -> cvss30 CVSS20 -> cvss20 @@ -189,18 +195,271 @@ data MetricValue = MetricValue mvDesc :: Text } +-- | CVSS4.0 metrics pulled from the specification https://www.first.org/cvss/v4.0/specification-document cvss40 :: CVSSDB cvss40 = CVSSDB [ MetricGroup "Base" baseMetrics, - MetricGroup "Temporal" temporalMetrics, - MetricGroup "Environmental" environmentalMetrics + MetricGroup "Threat" threatMetrics, + MetricGroup "Environmental" environmentalMetrics, + MetricGroup "Supplemental" supplementalMetrics ] where - baseMetrics = [] - temporalMetrics = [] - environmentalMetrics = [] + baseMetrics = [ MetricInfo + "Attack Vector" + "AV" + True + [MetricValue "Network" (C 'N') 0.0 Nothing "The vulnerable system is bound to the network stack and the set of possible attackers extends beyond the other options listed below, up to and including the entire Internet. Such a vulnerability is often termed “remotely exploitable” and can be thought of as an attack being exploitable at the protocol level one or more network hops away (e.g., across one or more routers)." + ,MetricValue "Adjacent" (C 'A') 0.0 Nothing "The vulnerable system is bound to a protocol stack, but the attack is limited at the protocol level to a logically adjacent topology. This can mean an attack must be launched from the same shared proximity (e.g., Bluetooth, NFC, or IEEE 802.11) or logical network (e.g., local IP subnet), or from within a secure or otherwise limited administrative domain (e.g., MPLS, secure VPN within an administrative network zone)." + ,MetricValue "Local" (C 'L') 0.0 Nothing "The vulnerable system is not bound to the network stack and the attacker’s path is via read/write/execute capabilities. Either the attacker exploits the vulnerability by accessing the target system locally (e.g., keyboard, console), or through terminal emulation (e.g., SSH); or the attacker relies on User Interaction by another person to perform actions required to exploit the vulnerability (e.g., using social engineering techniques to trick a legitimate user into opening a malicious document)." + ,MetricValue "Physical" (C 'P') 0.0 Nothing "The attack requires the attacker to physically touch or manipulate the vulnerable system. Physical interaction may be brief (e.g., evil maid attack) or persistent."] + ,MetricInfo + "Attack Complexity" + "AC" + True + [MetricValue "Low" (C 'L') 0.0 Nothing "The attacker must take no measurable action to exploit the vulnerability. The attack requires no target-specific circumvention to exploit the vulnerability. An attacker can expect repeatable success against the vulnerable system." + ,MetricValue "High" (C 'H') 0.0 Nothing "The successful attack depends on the evasion or circumvention of security-enhancing techniques in place that would otherwise hinder the attack. These include: Evasion of exploit mitigation techniques, for example, circumvention of address space randomization (ASLR) or data execution prevention (DEP) must be performed for the attack to be successful; Obtaining target-specific secrets. The attacker must gather some target-specific secret before the attack can be successful. A secret is any piece of information that cannot be obtained through any amount of reconnaissance. To obtain the secret the attacker must perform additional attacks or break otherwise secure measures (e.g. knowledge of a secret key may be needed to break a crypto channel). This operation must be performed for each attacked target."] + ,MetricInfo + "Attack Requirements" + "AT" + True + [MetricValue "None" (C 'N') 0.0 Nothing "The successful attack does not depend on the deployment and execution conditions of the vulnerable system. The attacker can expect to be able to reach the vulnerability and execute the exploit under all or most instances of the vulnerability." + ,MetricValue "Present" (C 'P') 0.0 Nothing "The successful attack depends on the presence of specific deployment and execution conditions of the vulnerable system that enable the attack. These include: a race condition must be won to successfully exploit the vulnerability (the successfulness of the attack is conditioned on execution conditions that are not under full control of the attacker, or the attack may need to be launched multiple times against a single target before being successful); the attacker must inject themselves into the logical network path between the target and the resource requested by the victim (e.g. vulnerabilities requiring an on-path attacker)."] + ,MetricInfo + "Privileges Required" + "PR" + True + [MetricValue "None" (C 'N') 0.0 Nothing "The attacker is unauthorized prior to attack, and therefore does not require any access to settings or files of the vulnerable system to carry out an attack." + ,MetricValue "Low" (C 'L') 0.0 Nothing "The attacker requires privileges that provide basic capabilities that are typically limited to settings and resources owned by a single low-privileged user. Alternatively, an attacker with Low privileges has the ability to access only non-sensitive resources." + ,MetricValue "High" (C 'H') 0.0 Nothing "The attacker requires privileges that provide significant (e.g., administrative) control over the vulnerable system allowing full access to the vulnerable system’s settings and files."] + ,MetricInfo + "User Interaction" + "UI" + True + [MetricValue "None" (C 'N') 0.0 Nothing "The vulnerable system can be exploited without interaction from any human user, other than the attacker." + ,MetricValue "Passive" (C 'P') 0.0 Nothing "Successful exploitation of this vulnerability requires limited interaction by the targeted user with the vulnerable system and the attacker’s payload. These interactions would be considered involuntary and do not require that the user actively subvert protections built into the vulnerable system." + ,MetricValue "Active" (C 'A') 0.0 Nothing "Successful exploitation of this vulnerability requires a targeted user to perform specific, conscious interactions with the vulnerable system and the attacker’s payload, or the user’s interactions would actively subvert protection mechanisms which would lead to exploitation of the vulnerability."] + ,MetricInfo + "Confidentiality" + "VC" + True + [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of confidentiality, resulting in all information within the Vulnerable System being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server." + ,MetricValue "Low" (C 'L') 0.0 Nothing "There is some loss of confidentiality. Access to some restricted information is obtained, but the attacker does not have control over what information is obtained, or the amount or kind of loss is limited. The information disclosure does not cause a direct, serious loss to the Vulnerable System." + ,MetricValue "None" (C 'N') 0.0 Nothing "There is no loss of confidentiality within the Vulnerable System."] + ,MetricInfo + "Integrity" + "VI" + True + [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the vulnerable system. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the vulnerable system." + ,MetricValue "Low" (C 'L') 0.0 Nothing "Modification of data is possible, but the attacker does not have control over the consequence of a modification, or the amount of modification is limited. The data modification does not have a direct, serious impact to the Vulnerable System." + ,MetricValue "None" (C 'N') 0.0 Nothing "There is no loss of integrity within the Vulnerable System."] + ,MetricInfo + "Availability" + "VA" + True + [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the Vulnerable System; this loss is either sustained (while the attacker continues to deliver the attack) or persistent (the condition persists even after the attack has completed). Alternatively, the attacker has the ability to deny some availability, but the loss of availability presents a direct, serious consequence to the Vulnerable System (e.g., the attacker cannot disrupt existing connections, but can prevent new connections; the attacker can repeatedly exploit a vulnerability that, in each instance of a successful attack, leaks a only small amount of memory, but after repeated exploitation causes a service to become completely unavailable)." + ,MetricValue "Low" (C 'L') 0.0 Nothing "Performance is reduced or there are interruptions in resource availability. Even if repeated exploitation of the vulnerability is possible, the attacker does not have the ability to completely deny service to legitimate users. The resources in the Vulnerable System are either partially available all of the time, or fully available only some of the time, but overall there is no direct, serious consequence to the Vulnerable System." + ,MetricValue "None" (C 'N') 0.0 Nothing "There is no impact to availability within the Vulnerable System."] + ,MetricInfo + "Confidentiality" + "SC" + True + [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of confidentiality, resulting in all resources within the Subsequent System being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server." + ,MetricValue "Low" (C 'L') 0.0 Nothing "There is some loss of confidentiality. Access to some restricted information is obtained, but the attacker does not have control over what information is obtained, or the amount or kind of loss is limited. The information disclosure does not cause a direct, serious loss to the Subsequent System." + ,MetricValue "None" (C 'N') 0.0 Nothing "There is no loss of confidentiality within the Subsequent System or all confidentiality impact is constrained to the Vulnerable System."] + ,MetricInfo + "Integrity" + "SI" + True + [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the Subsequent System. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the Subsequent System." + ,MetricValue "Low" (C 'L') 0.0 Nothing "Modification of data is possible, but the attacker does not have control over the consequence of a modification, or the amount of modification is limited. The data modification does not have a direct, serious impact to the Subsequent System." + ,MetricValue "None" (C 'N') 0.0 Nothing "There is no loss of integrity within the Subsequent System or all integrity impact is constrained to the Vulnerable System."] + ,MetricInfo + "Availability" + "SA" + True + [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the Subsequent System; this loss is either sustained (while the attacker continues to deliver the attack) or persistent (the condition persists even after the attack has completed). Alternatively, the attacker has the ability to deny some availability, but the loss of availability presents a direct, serious consequence to the Subsequent System (e.g., the attacker cannot disrupt existing connections, but can prevent new connections; the attacker can repeatedly exploit a vulnerability that, in each instance of a successful attack, leaks a only small amount of memory, but after repeated exploitation causes a service to become completely unavailable)." + ,MetricValue "Low" (C 'L') 0.0 Nothing "Performance is reduced or there are interruptions in resource availability. Even if repeated exploitation of the vulnerability is possible, the attacker does not have the ability to completely deny service to legitimate users. The resources in the Subsequent System are either partially available all of the time, or fully available only some of the time, but overall there is no direct, serious consequence to the Subsequent System." + ,MetricValue "None" (C 'N') 0.0 Nothing "There is no impact to availability within the Subsequent System or all availability impact is constrained to the Vulnerable System."] + ] + threatMetrics = [MetricInfo + "Exploit Maturity" + "E" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The Exploit Maturity metric is not being used. Reliable threat intelligence is not available to determine Exploit Maturity characteristics." + ,MetricValue "Attacked" (C 'A') 0.0 Nothing "Based on threat intelligence sources either of the following must apply: Attacks targeting this vulnerability (attempted or successful) have been reported Solutions to simplify attempts to exploit the vulnerability are publicly or privately available (such as exploit toolkits)" + ,MetricValue "POC" (C 'P') 0.0 Nothing "Based on threat intelligence sources each of the following must apply: Proof-of-concept is publicly available No knowledge of reported attempts to exploit this vulnerability No knowledge of publicly available solutions used to simplify attempts to exploit the vulnerability" + ,MetricValue "Unreported" (C 'U') 0.0 Nothing "Based on threat intelligence sources each of the following must apply: No knowledge of publicly available proof-of-concept No knowledge of reported attempts to exploit this vulnerability No knowledge of publicly available solutions used to simplify attempts to exploit the vulnerability"] + ] + environmentalMetrics = [MetricInfo + "Attack Vector" + "MAV" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "Network" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Adjacent" (C 'A') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Local" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Physical" (C 'P') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Attack Complexity" + "MAC" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Attack Requirements" + "MAT" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Present" (C 'P') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Privileges Required" + "MPR" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "User Interaction" + "MUI" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Passive" (C 'P') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Active" (C 'A') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Confidentiality" + "MVC" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Integrity" + "MVI" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Availability" + "MVA" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Confidentiality" + "MSC" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Negligible" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Integrity" + "MSI" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "Safety" (C 'S') 0.0 Nothing "The exploited vulnerability will result in integrity impacts that could cause serious injury or worse (categories of \"Marginal\" or worse as described in IEC 61508) to a human actor or participant." + ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Negligible" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Availability" + "MSA" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "Safety" (C 'S') 0.0 Nothing "The exploited vulnerability will result in availability impacts that could cause serious injury or worse (categories of \"Marginal\" or worse as described in IEC 61508) to a human actor or participant." + ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Negligible" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricInfo + "Confidentiality Requirements" + "CR" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "Assigning this value indicates there is insufficient information to choose one of the other values, and has no impact on the overall Environmental Score" + ,MetricValue "High" (C 'H') 0.0 Nothing "Loss of Confidentiality is likely to have a catastrophic adverse effect on the organization or individuals associated with the organization." + ,MetricValue "Medium" (C 'M') 0.0 Nothing "Loss of Confidentiality is likely to have a serious adverse effect on the organization or individuals associated with the organization." + ,MetricValue "Low" (C 'L') 0.0 Nothing "Loss of Confidentiality is likely to have only a limited adverse effect on the organization or individuals associated with the organization."] + ,MetricInfo + "Integrity Requirements" + "IR" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "Assigning this value indicates there is insufficient information to choose one of the other values, and has no impact on the overall Environmental Score" + ,MetricValue "High" (C 'H') 0.0 Nothing "Loss of Integrity is likely to have a catastrophic adverse effect on the organization or individuals associated with the organization." + ,MetricValue "Medium" (C 'M') 0.0 Nothing "Loss of Integrity is likely to have a serious adverse effect on the organization or individuals associated with the organization." + ,MetricValue "Low" (C 'L') 0.0 Nothing "Loss of Integrity is likely to have only a limited adverse effect on the organization or individuals associated with the organization."] + ,MetricInfo + "Availability Requirements" + "AR" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "Assigning this value indicates there is insufficient information to choose one of the other values, and has no impact on the overall Environmental Score" + ,MetricValue "High" (C 'H') 0.0 Nothing "Loss of Availability is likely to have a catastrophic adverse effect on the organization or individuals associated with the organization." + ,MetricValue "Medium" (C 'M') 0.0 Nothing "Loss of Availability is likely to have a serious adverse effect on the organization or individuals associated with the organization." + ,MetricValue "Low" (C 'L') 0.0 Nothing "Loss of Availability is likely to have only a limited adverse effect on the organization or individuals associated with the organization."] + ] + supplementalMetrics = [MetricInfo + "Safety" + "S" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "Negligible" (C 'N') 0.0 Nothing "Consequences of the vulnerability meet definition of IEC 61508 consequence category \"negligible.\"" + ,MetricValue "Present" (C 'P') 0.0 Nothing "Consequences of the vulnerability meet definition of IEC 61508 consequence categories of \"marginal,\" \"critical,\" or \"catastrophic.\""] + ,MetricInfo + "Automatable" + "AU" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "No" (C 'N') 0.0 Nothing "Attackers cannot reliably automate all 4 steps of the kill chain for this vulnerability for some reason. These steps are reconnaissance, weaponization, delivery, and exploitation." + ,MetricValue "Yes" (C 'Y') 0.0 Nothing "Attackers can reliably automate all 4 steps of the kill chain. These steps are reconnaissance, weaponization, delivery, and exploitation (e.g., the vulnerability is “wormable”)."] + ,MetricInfo + "Recovery" + "R" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "Automatic" (C 'A') 0.0 Nothing "The system recovers services automatically after an attack has been performed." + ,MetricValue "User" (C 'U') 0.0 Nothing "The system requires manual intervention by the user to recover services, after an attack has been performed." + ,MetricValue "Irrecoverable" (C 'I') 0.0 Nothing "The system services are irrecoverable by the user, after an attack has been performed."] + ,MetricInfo + "Value Density" + "V" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "Diffuse" (C 'D') 0.0 Nothing "The vulnerable system has limited resources. That is, the resources that the attacker will gain control over with a single exploitation event are relatively small. An example of Diffuse (think: limited) Value Density would be an attack on a single email client vulnerability." + ,MetricValue "Concentrated" (C 'C') 0.0 Nothing "The vulnerable system is rich in resources. Heuristically, such systems are often the direct responsibility of “system operators” rather than users. An example of Concentrated (think: broad) Value Density would be an attack on a central email server."] + ,MetricInfo + "Vulnerability Response Effort" + "RE" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "Low" (C 'L') 0.0 Nothing "The effort required to respond to a vulnerability is low/trivial. Examples include: communication on better documentation, configuration workarounds, or guidance from the vendor that does not require an immediate update, upgrade, or replacement by the consuming entity, such as firewall filter configuration." + ,MetricValue "Moderate" (C 'M') 0.0 Nothing "The actions required to respond to a vulnerability require some effort on behalf of the consumer and could cause minimal service impact to implement. Examples include: simple remote update, disabling of a subsystem, or a low-touch software upgrade such as a driver update." + ,MetricValue "High" (C 'H') 0.0 Nothing "The actions required to respond to a vulnerability are significant and/or difficult, and may possibly lead to an extended, scheduled service impact. This would need to be considered for scheduling purposes including honoring any embargo on deployment of the selected response. Alternatively, response to the vulnerability in the field is not possible remotely. The only resolution to the vulnerability involves physical replacement (e.g. units deployed would have to be recalled for a depot level repair or replacement). Examples include: a highly privileged driver update, microcode or UEFI BIOS updates, or software upgrades requiring careful analysis and understanding of any potential infrastructure impact before implementation. A UEFI BIOS update that impacts Trusted Platform Module (TPM) attestation without impacting disk encryption software such as Bit locker is a good recent example. Irreparable failures such as non-bootable flash subsystems, failed disks or solid-state drives (SSD), bad memory modules, network devices, or other non-recoverable under warranty hardware, should also be scored as having a High effort."] + ,MetricInfo + "Provider Urgency" + "U" + False + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated."] + -- ,MetricValue "Clear" (C 'Clear') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having no urgency (Informational)." + -- ,MetricValue "Green" (C 'Green') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having a reduced urgency." + -- ,MetricValue "Amber" (C 'Amber') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having a moderate urgency." + -- ,MetricValue "Red" (C 'Red') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having the highest urgency."] + ] + +validateCvss40 :: [Metric] -> Either CVSSError [Metric] +validateCvss40 metrics = do + traverse_ (\t -> t metrics) [validateUnique, validateKnown cvss40, validateRequired cvss40] + pure metrics +cvss40score :: [Metric] -> (Rating, Float) +cvss40score metrics = undefined -- | CVSS3.1 metrics pulled from section 2. "Base Metrics" and section section 7.4. "Metric Values" cvss31 :: CVSSDB diff --git a/code/cvss/test/Spec.hs b/code/cvss/test/Spec.hs index 6e092da3..aa6d91b4 100644 --- a/code/cvss/test/Spec.hs +++ b/code/cvss/test/Spec.hs @@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE BlockArguments #-} module Main where @@ -9,30 +10,49 @@ import Test.Tasty.HUnit main :: IO () main = defaultMain $ - testGroup "Security.CVSS" $ - map runTest testCases where - runTest (cvssString, score, rating) = testCase (unpack cvssString) $ - case CVSS.parseCVSS cvssString of - Left e -> assertFailure (show e) - Right cvss -> do - CVSS.cvssScore cvss @?= (rating, score) - CVSS.cvssVectorString cvss @?= cvssString - CVSS.cvssVectorStringOrdered cvss @?= cvssString - -testCases :: [(Text, Float, CVSS.Rating)] -testCases = - [--("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/S:P/AU:Y/V:C/RE:L", 9.4, CVSS.Critical) - ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 8.8, CVSS.High) - , ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N", 5.8, CVSS.Medium) - , ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N", 6.4, CVSS.Medium) - , ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.1, CVSS.Low) - , ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", 6.1, CVSS.Medium) + testGroup "Security.CVSS" [ + testGroup "Security.CVSS:2.0" $ runTest testCases20 + , testGroup "Security.CVSS:3.0" $ runTest testCases30 + , testGroup "Security.CVSS:3.1" $ runTest testCases31 + -- , testGroup "Security.CVSS:4.0" $ runTest testCases40 + ] + +runTest :: [(Text, Float, CVSS.Rating)] -> [TestTree] +runTest = map \(cvssString, score, rating) -> testCase (unpack cvssString) $ + case CVSS.parseCVSS cvssString of + Left e -> assertFailure (show e) + Right cvss -> do + CVSS.cvssScore cvss @?= (rating, score) + CVSS.cvssVectorString cvss @?= cvssString + CVSS.cvssVectorStringOrdered cvss @?= cvssString + +testCases30 :: [(Text, Float, CVSS.Rating)] +testCases30 = + [("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", 6.1, CVSS.Medium) , ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N", 6.4, CVSS.Medium) , ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.1, CVSS.Low) , ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 4.0, CVSS.Medium) , ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", 9.9, CVSS.Critical) , ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L", 4.2, CVSS.Medium) - , ("CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:C", 7.8, CVSS.High) + ] + +testCases31 :: [(Text, Float, CVSS.Rating)] +testCases31 = + [("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 8.8, CVSS.High) + , ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N", 5.8, CVSS.Medium) + , ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N", 6.4, CVSS.Medium) + , ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.1, CVSS.Low) + ] + +testCases20 :: [(Text, Float, CVSS.Rating)] +testCases20 = + [("CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:C", 7.8, CVSS.High) , ("CVSS:2.0/AV:N/AC:L/Au:N/C:C/I:C/A:C", 10, CVSS.Critical) , ("CVSS:2.0/AV:L/AC:H/Au:N/C:C/I:C/A:C", 6.2, CVSS.Medium) ] + +testCases40 :: [(Text, Float, CVSS.Rating)] +testCases40 = + [("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/S:P/AU:Y/V:C/RE:L", 9.4, CVSS.Critical) + , ("CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 7.3, CVSS.High) + ] From 53c3280d435692276fd356e6029c7eb348d98aa6 Mon Sep 17 00:00:00 2001 From: unorsk <25188+unorsk@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:30:57 +0200 Subject: [PATCH 3/6] adding cvss40 support + tests --- code/cvss/cvss.cabal | 9 +- code/cvss/src/Security/CVSS.hs | 435 ++++++++++++++++++++----- code/cvss/src/Security/CVSS40Lookup.hs | 325 ++++++++++++++++++ code/cvss/test/Spec.hs | 57 +++- 4 files changed, 729 insertions(+), 97 deletions(-) create mode 100644 code/cvss/src/Security/CVSS40Lookup.hs diff --git a/code/cvss/cvss.cabal b/code/cvss/cvss.cabal index f9d1fbb1..fcbd11ff 100644 --- a/code/cvss/cvss.cabal +++ b/code/cvss/cvss.cabal @@ -10,13 +10,16 @@ author: Tristan de Cacqueray maintainer: tdecacqu@redhat.com category: Data extra-doc-files: CHANGELOG.md -tested-with: GHC ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.3 || ==9.8.1 +tested-with: + GHC ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.3 || ==9.8.1 library exposed-modules: Security.CVSS + other-modules: Security.CVSS40Lookup build-depends: - , base >=4.14 && <5 - , text >=1.2 && <3 + , base >=4.14 && <5 + , containers + , text >=1.2 && <3 hs-source-dirs: src default-language: Haskell2010 diff --git a/code/cvss/src/Security/CVSS.hs b/code/cvss/src/Security/CVSS.hs index fa0cae21..59c07351 100644 --- a/code/cvss/src/Security/CVSS.hs +++ b/code/cvss/src/Security/CVSS.hs @@ -28,11 +28,14 @@ where import Data.Coerce (coerce) import Data.Foldable (traverse_) import Data.List (find, group, sort) -import Data.Maybe (mapMaybe) +import Data.Maybe (mapMaybe, fromMaybe) import Data.String (IsString) import Data.Text (Text) import Data.Text qualified as Text import GHC.Float (powerFloat) +import Security.CVSS40Lookup (lookupScore, maxComposed, maxComposedEQ3, maxSeverity, maxSeverityeq3eq6) +import qualified Data.Map as Map +import Data.Either (rights) -- | The CVSS version. data CVSSVersion @@ -54,6 +57,112 @@ data CVSS = CVSS cvssMetrics :: [Metric] } +data CVSSScore = Zero | One | Two deriving (Show) + +toText :: MetricShortName -> Text +toText (MetricShortName t) = t + +defaultMetricValue :: MetricShortName -> Maybe MetricValueChar +defaultMetricValue metricValue = + let isXValue = elem metricValue ["MAV", "MAC", "MAT", "MPR", "MUI", "MVC", "MVI", "MSC", "MSA", "MSI", "S", "AU", "R", "V", "RE", "U"] + isAValue = elem metricValue ["E"] + isHValue = elem metricValue ["CR", "IR", "AR"] in + if isXValue then Just $ C 'X' else + if isAValue then Just $ C 'A' else + if isHValue then Just $ C 'H' else Nothing + + +getCvssMetric :: [Metric] -> MetricShortName -> Maybe Metric +getCvssMetric metrics shortName = find (\c -> mName c == shortName) metrics + +getCvssMetricChar :: [Metric] -> MetricShortName -> Maybe MetricValueChar +getCvssMetricChar metrics shortName = case getCvssMetric metrics shortName of + Just c -> Just $ mChar c + Nothing -> Nothing + +getCvssMetricCharOverriden :: [Metric] -> MetricShortName -> Maybe MetricValueChar +getCvssMetricCharOverriden metrics shortName = + let + overridingName = MetricShortName (Text.pack $ "M" <> Text.unpack (toText shortName)) + overridingMetricChar = getCvssMetricChar metrics overridingName + metricChar = getCvssMetricChar metrics shortName + defaultMetricChar = defaultMetricValue shortName in + case overridingMetricChar of + Just _ -> overridingMetricChar + Nothing -> case metricChar of + Just _ -> metricChar + Nothing -> case defaultMetricChar of + Just _ -> defaultMetricChar + Nothing -> Nothing + +getCvssMetricV :: CVSSDB -> [Metric] -> MetricShortName -> Float +getCvssMetricV db metrics shortName = + let metricChar = getCvssMetricCharOverriden metrics shortName in + case metricChar of + Just c -> let v = concatMap miValues (filter (\m -> miShortName m == shortName) $ allMetrics db) in + case find (\mv -> mvChar mv == c) v of + Just metricValue -> mvNum metricValue + Nothing -> 0.0 + Nothing -> 0.0 + + +hasCvssMetricWithValueR :: [Metric] -> MetricShortName -> MetricValueChar -> Bool +hasCvssMetricWithValueR metrics shortName mchar = + case getCvssMetricCharOverriden metrics shortName of + Just c -> c == mchar + Nothing -> False + +castCVSSScoreToInt :: CVSSScore -> Int +castCVSSScoreToInt Zero = 0 +castCVSSScoreToInt One = 1 +castCVSSScoreToInt Two = 2 + +calcEq1 :: [Metric] -> CVSSScore +calcEq1 metrics = + let hasC = hasCvssMetricWithValueR metrics in + if hasC "AV" (C 'N') && hasC "PR" (C 'N') && hasC "UI" (C 'N') then Zero else + (if (hasC "AV" (C 'N') || hasC "PR" (C 'N') || hasC "UI" (C 'N')) && + not (hasC "AV" (C 'N') && hasC "PR" (C 'N') && hasC "UI" (C 'N')) && + not (hasC "AV" (C 'P')) then One else Two)--(if hasC "AV" (C 'P') || not (hasC "AV" (C 'N') || hasC "PR" (C 'N') || hasC "UI" (C 'N')) then Two else error "blabla EQ1")) + +calcEq2 :: [Metric] -> CVSSScore +calcEq2 metrics = + let hasC = hasCvssMetricWithValueR metrics in + if hasC "AC" (C 'L') && hasC "AT" (C 'N') then Zero else One + +calcEq3 :: [Metric] -> CVSSScore +calcEq3 metrics = + let hasC = hasCvssMetricWithValueR metrics in + if hasC "VC" (C 'H') && hasC "VI" (C 'H') then Zero else + if hasC "VC" (C 'H') || hasC "VI" (C 'H') || hasC "VA" (C 'H') then One else Two + +calcEq4 :: [Metric] -> CVSSScore +calcEq4 metrics = + let hasC = hasCvssMetricWithValueR metrics in + if hasC "MSI" (C 'S') || hasC "MSA" (C 'S') then Zero else + if hasC "SC" (C 'H') || hasC "SI" (C 'H') || hasC "SA" (C 'H') then One else Two + + +calcEq5 :: [Metric] -> CVSSScore +calcEq5 metrics = + let hasC = hasCvssMetricWithValueR metrics in + if hasC "E" (C 'A') then Zero else + if hasC "E" (C 'P') then One else + if hasC "E" (C 'U') then Two else Zero + +calcEq6 :: [Metric] -> CVSSScore +calcEq6 metrics = + let hasC = hasCvssMetricWithValueR metrics in + if (hasC "CR" (C 'H') && hasC "VC" (C 'H')) + || (hasC "IR" (C 'H') && hasC "VI" (C 'H')) + || (hasC "AR" (C 'H') && hasC "VA" (C 'H')) then Zero else + if not ((hasC "CR" (C 'H') && hasC "VC" (C 'H')) + || (hasC "IR" (C 'H') && hasC "VI" (C 'H')) + || (hasC "AR" (C 'H') && hasC "VA" (C 'H'))) then One else + -- if hasC "CR" (C 'X') || hasC "IR" (C 'X') || hasC "AR" (C 'X') then Zero else + Zero + + instance Show CVSS where show = Text.unpack . cvssVectorString @@ -205,82 +314,82 @@ cvss40 = MetricGroup "Supplemental" supplementalMetrics ] where - baseMetrics = [ MetricInfo - "Attack Vector" - "AV" - True + baseMetrics = [ MetricInfo + "Attack Vector" + "AV" + True [MetricValue "Network" (C 'N') 0.0 Nothing "The vulnerable system is bound to the network stack and the set of possible attackers extends beyond the other options listed below, up to and including the entire Internet. Such a vulnerability is often termed “remotely exploitable” and can be thought of as an attack being exploitable at the protocol level one or more network hops away (e.g., across one or more routers)." - ,MetricValue "Adjacent" (C 'A') 0.0 Nothing "The vulnerable system is bound to a protocol stack, but the attack is limited at the protocol level to a logically adjacent topology. This can mean an attack must be launched from the same shared proximity (e.g., Bluetooth, NFC, or IEEE 802.11) or logical network (e.g., local IP subnet), or from within a secure or otherwise limited administrative domain (e.g., MPLS, secure VPN within an administrative network zone)." - ,MetricValue "Local" (C 'L') 0.0 Nothing "The vulnerable system is not bound to the network stack and the attacker’s path is via read/write/execute capabilities. Either the attacker exploits the vulnerability by accessing the target system locally (e.g., keyboard, console), or through terminal emulation (e.g., SSH); or the attacker relies on User Interaction by another person to perform actions required to exploit the vulnerability (e.g., using social engineering techniques to trick a legitimate user into opening a malicious document)." - ,MetricValue "Physical" (C 'P') 0.0 Nothing "The attack requires the attacker to physically touch or manipulate the vulnerable system. Physical interaction may be brief (e.g., evil maid attack) or persistent."] - ,MetricInfo - "Attack Complexity" - "AC" - True + ,MetricValue "Adjacent" (C 'A') 0.1 Nothing "The vulnerable system is bound to a protocol stack, but the attack is limited at the protocol level to a logically adjacent topology. This can mean an attack must be launched from the same shared proximity (e.g., Bluetooth, NFC, or IEEE 802.11) or logical network (e.g., local IP subnet), or from within a secure or otherwise limited administrative domain (e.g., MPLS, secure VPN within an administrative network zone)." + ,MetricValue "Local" (C 'L') 0.2 Nothing "The vulnerable system is not bound to the network stack and the attacker’s path is via read/write/execute capabilities. Either the attacker exploits the vulnerability by accessing the target system locally (e.g., keyboard, console), or through terminal emulation (e.g., SSH); or the attacker relies on User Interaction by another person to perform actions required to exploit the vulnerability (e.g., using social engineering techniques to trick a legitimate user into opening a malicious document)." + ,MetricValue "Physical" (C 'P') 0.3 Nothing "The attack requires the attacker to physically touch or manipulate the vulnerable system. Physical interaction may be brief (e.g., evil maid attack) or persistent."] + ,MetricInfo + "Attack Complexity" + "AC" + True [MetricValue "Low" (C 'L') 0.0 Nothing "The attacker must take no measurable action to exploit the vulnerability. The attack requires no target-specific circumvention to exploit the vulnerability. An attacker can expect repeatable success against the vulnerable system." - ,MetricValue "High" (C 'H') 0.0 Nothing "The successful attack depends on the evasion or circumvention of security-enhancing techniques in place that would otherwise hinder the attack. These include: Evasion of exploit mitigation techniques, for example, circumvention of address space randomization (ASLR) or data execution prevention (DEP) must be performed for the attack to be successful; Obtaining target-specific secrets. The attacker must gather some target-specific secret before the attack can be successful. A secret is any piece of information that cannot be obtained through any amount of reconnaissance. To obtain the secret the attacker must perform additional attacks or break otherwise secure measures (e.g. knowledge of a secret key may be needed to break a crypto channel). This operation must be performed for each attacked target."] - ,MetricInfo - "Attack Requirements" - "AT" - True + ,MetricValue "High" (C 'H') 0.1 Nothing "The successful attack depends on the evasion or circumvention of security-enhancing techniques in place that would otherwise hinder the attack. These include: Evasion of exploit mitigation techniques, for example, circumvention of address space randomization (ASLR) or data execution prevention (DEP) must be performed for the attack to be successful; Obtaining target-specific secrets. The attacker must gather some target-specific secret before the attack can be successful. A secret is any piece of information that cannot be obtained through any amount of reconnaissance. To obtain the secret the attacker must perform additional attacks or break otherwise secure measures (e.g. knowledge of a secret key may be needed to break a crypto channel). This operation must be performed for each attacked target."] + ,MetricInfo + "Attack Requirements" + "AT" + True [MetricValue "None" (C 'N') 0.0 Nothing "The successful attack does not depend on the deployment and execution conditions of the vulnerable system. The attacker can expect to be able to reach the vulnerability and execute the exploit under all or most instances of the vulnerability." - ,MetricValue "Present" (C 'P') 0.0 Nothing "The successful attack depends on the presence of specific deployment and execution conditions of the vulnerable system that enable the attack. These include: a race condition must be won to successfully exploit the vulnerability (the successfulness of the attack is conditioned on execution conditions that are not under full control of the attacker, or the attack may need to be launched multiple times against a single target before being successful); the attacker must inject themselves into the logical network path between the target and the resource requested by the victim (e.g. vulnerabilities requiring an on-path attacker)."] - ,MetricInfo - "Privileges Required" - "PR" - True + ,MetricValue "Present" (C 'P') 0.1 Nothing "The successful attack depends on the presence of specific deployment and execution conditions of the vulnerable system that enable the attack. These include: a race condition must be won to successfully exploit the vulnerability (the successfulness of the attack is conditioned on execution conditions that are not under full control of the attacker, or the attack may need to be launched multiple times against a single target before being successful); the attacker must inject themselves into the logical network path between the target and the resource requested by the victim (e.g. vulnerabilities requiring an on-path attacker)."] + ,MetricInfo + "Privileges Required" + "PR" + True [MetricValue "None" (C 'N') 0.0 Nothing "The attacker is unauthorized prior to attack, and therefore does not require any access to settings or files of the vulnerable system to carry out an attack." - ,MetricValue "Low" (C 'L') 0.0 Nothing "The attacker requires privileges that provide basic capabilities that are typically limited to settings and resources owned by a single low-privileged user. Alternatively, an attacker with Low privileges has the ability to access only non-sensitive resources." - ,MetricValue "High" (C 'H') 0.0 Nothing "The attacker requires privileges that provide significant (e.g., administrative) control over the vulnerable system allowing full access to the vulnerable system’s settings and files."] - ,MetricInfo - "User Interaction" - "UI" - True + ,MetricValue "Low" (C 'L') 0.1 Nothing "The attacker requires privileges that provide basic capabilities that are typically limited to settings and resources owned by a single low-privileged user. Alternatively, an attacker with Low privileges has the ability to access only non-sensitive resources." + ,MetricValue "High" (C 'H') 0.2 Nothing "The attacker requires privileges that provide significant (e.g., administrative) control over the vulnerable system allowing full access to the vulnerable system’s settings and files."] + ,MetricInfo + "User Interaction" + "UI" + True [MetricValue "None" (C 'N') 0.0 Nothing "The vulnerable system can be exploited without interaction from any human user, other than the attacker." - ,MetricValue "Passive" (C 'P') 0.0 Nothing "Successful exploitation of this vulnerability requires limited interaction by the targeted user with the vulnerable system and the attacker’s payload. These interactions would be considered involuntary and do not require that the user actively subvert protections built into the vulnerable system." - ,MetricValue "Active" (C 'A') 0.0 Nothing "Successful exploitation of this vulnerability requires a targeted user to perform specific, conscious interactions with the vulnerable system and the attacker’s payload, or the user’s interactions would actively subvert protection mechanisms which would lead to exploitation of the vulnerability."] - ,MetricInfo - "Confidentiality" - "VC" - True + ,MetricValue "Passive" (C 'P') 0.1 Nothing "Successful exploitation of this vulnerability requires limited interaction by the targeted user with the vulnerable system and the attacker’s payload. These interactions would be considered involuntary and do not require that the user actively subvert protections built into the vulnerable system." + ,MetricValue "Active" (C 'A') 0.2 Nothing "Successful exploitation of this vulnerability requires a targeted user to perform specific, conscious interactions with the vulnerable system and the attacker’s payload, or the user’s interactions would actively subvert protection mechanisms which would lead to exploitation of the vulnerability."] + ,MetricInfo + "Confidentiality" + "VC" + True [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of confidentiality, resulting in all information within the Vulnerable System being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server." - ,MetricValue "Low" (C 'L') 0.0 Nothing "There is some loss of confidentiality. Access to some restricted information is obtained, but the attacker does not have control over what information is obtained, or the amount or kind of loss is limited. The information disclosure does not cause a direct, serious loss to the Vulnerable System." - ,MetricValue "None" (C 'N') 0.0 Nothing "There is no loss of confidentiality within the Vulnerable System."] - ,MetricInfo + ,MetricValue "Low" (C 'L') 0.1 Nothing "There is some loss of confidentiality. Access to some restricted information is obtained, but the attacker does not have control over what information is obtained, or the amount or kind of loss is limited. The information disclosure does not cause a direct, serious loss to the Vulnerable System." + ,MetricValue "None" (C 'N') 0.2 Nothing "There is no loss of confidentiality within the Vulnerable System."] + ,MetricInfo "Integrity" "VI" True [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the vulnerable system. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the vulnerable system." - ,MetricValue "Low" (C 'L') 0.0 Nothing "Modification of data is possible, but the attacker does not have control over the consequence of a modification, or the amount of modification is limited. The data modification does not have a direct, serious impact to the Vulnerable System." - ,MetricValue "None" (C 'N') 0.0 Nothing "There is no loss of integrity within the Vulnerable System."] + ,MetricValue "Low" (C 'L') 0.1 Nothing "Modification of data is possible, but the attacker does not have control over the consequence of a modification, or the amount of modification is limited. The data modification does not have a direct, serious impact to the Vulnerable System." + ,MetricValue "None" (C 'N') 0.2 Nothing "There is no loss of integrity within the Vulnerable System."] ,MetricInfo "Availability" "VA" - True + True [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the Vulnerable System; this loss is either sustained (while the attacker continues to deliver the attack) or persistent (the condition persists even after the attack has completed). Alternatively, the attacker has the ability to deny some availability, but the loss of availability presents a direct, serious consequence to the Vulnerable System (e.g., the attacker cannot disrupt existing connections, but can prevent new connections; the attacker can repeatedly exploit a vulnerability that, in each instance of a successful attack, leaks a only small amount of memory, but after repeated exploitation causes a service to become completely unavailable)." - ,MetricValue "Low" (C 'L') 0.0 Nothing "Performance is reduced or there are interruptions in resource availability. Even if repeated exploitation of the vulnerability is possible, the attacker does not have the ability to completely deny service to legitimate users. The resources in the Vulnerable System are either partially available all of the time, or fully available only some of the time, but overall there is no direct, serious consequence to the Vulnerable System." - ,MetricValue "None" (C 'N') 0.0 Nothing "There is no impact to availability within the Vulnerable System."] - ,MetricInfo + ,MetricValue "Low" (C 'L') 0.1 Nothing "Performance is reduced or there are interruptions in resource availability. Even if repeated exploitation of the vulnerability is possible, the attacker does not have the ability to completely deny service to legitimate users. The resources in the Vulnerable System are either partially available all of the time, or fully available only some of the time, but overall there is no direct, serious consequence to the Vulnerable System." + ,MetricValue "None" (C 'N') 0.2 Nothing "There is no impact to availability within the Vulnerable System."] + ,MetricInfo "Confidentiality" "SC" True - [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of confidentiality, resulting in all resources within the Subsequent System being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server." - ,MetricValue "Low" (C 'L') 0.0 Nothing "There is some loss of confidentiality. Access to some restricted information is obtained, but the attacker does not have control over what information is obtained, or the amount or kind of loss is limited. The information disclosure does not cause a direct, serious loss to the Subsequent System." - ,MetricValue "None" (C 'N') 0.0 Nothing "There is no loss of confidentiality within the Subsequent System or all confidentiality impact is constrained to the Vulnerable System."] + [MetricValue "High" (C 'H') 0.1 Nothing "There is a total loss of confidentiality, resulting in all resources within the Subsequent System being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server." + ,MetricValue "Low" (C 'L') 0.2 Nothing "There is some loss of confidentiality. Access to some restricted information is obtained, but the attacker does not have control over what information is obtained, or the amount or kind of loss is limited. The information disclosure does not cause a direct, serious loss to the Subsequent System." + ,MetricValue "None" (C 'N') 0.3 Nothing "There is no loss of confidentiality within the Subsequent System or all confidentiality impact is constrained to the Vulnerable System."] ,MetricInfo "Integrity" "SI" True - [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the Subsequent System. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the Subsequent System." - ,MetricValue "Low" (C 'L') 0.0 Nothing "Modification of data is possible, but the attacker does not have control over the consequence of a modification, or the amount of modification is limited. The data modification does not have a direct, serious impact to the Subsequent System." - ,MetricValue "None" (C 'N') 0.0 Nothing "There is no loss of integrity within the Subsequent System or all integrity impact is constrained to the Vulnerable System."] + [MetricValue "High" (C 'H') 0.1 Nothing "There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the Subsequent System. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the Subsequent System." + ,MetricValue "Low" (C 'L') 0.2 Nothing "Modification of data is possible, but the attacker does not have control over the consequence of a modification, or the amount of modification is limited. The data modification does not have a direct, serious impact to the Subsequent System." + ,MetricValue "None" (C 'N') 0.3 Nothing "There is no loss of integrity within the Subsequent System or all integrity impact is constrained to the Vulnerable System."] ,MetricInfo "Availability" "SA" True - [MetricValue "High" (C 'H') 0.0 Nothing "There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the Subsequent System; this loss is either sustained (while the attacker continues to deliver the attack) or persistent (the condition persists even after the attack has completed). Alternatively, the attacker has the ability to deny some availability, but the loss of availability presents a direct, serious consequence to the Subsequent System (e.g., the attacker cannot disrupt existing connections, but can prevent new connections; the attacker can repeatedly exploit a vulnerability that, in each instance of a successful attack, leaks a only small amount of memory, but after repeated exploitation causes a service to become completely unavailable)." - ,MetricValue "Low" (C 'L') 0.0 Nothing "Performance is reduced or there are interruptions in resource availability. Even if repeated exploitation of the vulnerability is possible, the attacker does not have the ability to completely deny service to legitimate users. The resources in the Subsequent System are either partially available all of the time, or fully available only some of the time, but overall there is no direct, serious consequence to the Subsequent System." - ,MetricValue "None" (C 'N') 0.0 Nothing "There is no impact to availability within the Subsequent System or all availability impact is constrained to the Vulnerable System."] + [MetricValue "High" (C 'H') 0.1 Nothing "There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the Subsequent System; this loss is either sustained (while the attacker continues to deliver the attack) or persistent (the condition persists even after the attack has completed). Alternatively, the attacker has the ability to deny some availability, but the loss of availability presents a direct, serious consequence to the Subsequent System (e.g., the attacker cannot disrupt existing connections, but can prevent new connections; the attacker can repeatedly exploit a vulnerability that, in each instance of a successful attack, leaks a only small amount of memory, but after repeated exploitation causes a service to become completely unavailable)." + ,MetricValue "Low" (C 'L') 0.2 Nothing "Performance is reduced or there are interruptions in resource availability. Even if repeated exploitation of the vulnerability is possible, the attacker does not have the ability to completely deny service to legitimate users. The resources in the Subsequent System are either partially available all of the time, or fully available only some of the time, but overall there is no direct, serious consequence to the Subsequent System." + ,MetricValue "None" (C 'N') 0.3 Nothing "There is no impact to availability within the Subsequent System or all availability impact is constrained to the Vulnerable System."] ] threatMetrics = [MetricInfo "Exploit Maturity" @@ -288,8 +397,8 @@ cvss40 = False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The Exploit Maturity metric is not being used. Reliable threat intelligence is not available to determine Exploit Maturity characteristics." ,MetricValue "Attacked" (C 'A') 0.0 Nothing "Based on threat intelligence sources either of the following must apply: Attacks targeting this vulnerability (attempted or successful) have been reported Solutions to simplify attempts to exploit the vulnerability are publicly or privately available (such as exploit toolkits)" - ,MetricValue "POC" (C 'P') 0.0 Nothing "Based on threat intelligence sources each of the following must apply: Proof-of-concept is publicly available No knowledge of reported attempts to exploit this vulnerability No knowledge of publicly available solutions used to simplify attempts to exploit the vulnerability" - ,MetricValue "Unreported" (C 'U') 0.0 Nothing "Based on threat intelligence sources each of the following must apply: No knowledge of publicly available proof-of-concept No knowledge of reported attempts to exploit this vulnerability No knowledge of publicly available solutions used to simplify attempts to exploit the vulnerability"] + ,MetricValue "POC" (C 'P') 0.1 Nothing "Based on threat intelligence sources each of the following must apply: Proof-of-concept is publicly available No knowledge of reported attempts to exploit this vulnerability No knowledge of publicly available solutions used to simplify attempts to exploit the vulnerability" + ,MetricValue "Unreported" (C 'U') 0.2 Nothing "Based on threat intelligence sources each of the following must apply: No knowledge of publicly available proof-of-concept No knowledge of reported attempts to exploit this vulnerability No knowledge of publicly available solutions used to simplify attempts to exploit the vulnerability"] ] environmentalMetrics = [MetricInfo "Attack Vector" @@ -297,115 +406,115 @@ cvss40 = False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "Network" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Adjacent" (C 'A') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Local" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Physical" (C 'P') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "Adjacent" (C 'A') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Local" (C 'L') 0.2 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Physical" (C 'P') 0.3 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "Attack Complexity" "MAC" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "High" (C 'H') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "Attack Requirements" "MAT" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Present" (C 'P') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "Present" (C 'P') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "Privileges Required" "MPR" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "Low" (C 'L') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "High" (C 'H') 0.2 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "User Interaction" "MUI" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Passive" (C 'P') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Active" (C 'A') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "Passive" (C 'P') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Active" (C 'A') 0.2 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "Confidentiality" "MVC" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "Low" (C 'L') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "None" (C 'N') 0.2 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "Integrity" "MVI" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "Low" (C 'L') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "None" (C 'N') 0.2 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "Availability" "MVA" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "None" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "Low" (C 'L') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "None" (C 'N') 0.2 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "Confidentiality" "MSC" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." - ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Negligible" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "High" (C 'H') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.2 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Negligible" (C 'N') 0.3 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo - "Integrity" + "Integrity" "MSI" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "Safety" (C 'S') 0.0 Nothing "The exploited vulnerability will result in integrity impacts that could cause serious injury or worse (categories of \"Marginal\" or worse as described in IEC 61508) to a human actor or participant." - ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Negligible" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "High" (C 'H') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.2 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Negligible" (C 'N') 0.3 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "Availability" "MSA" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." ,MetricValue "Safety" (C 'S') 0.0 Nothing "The exploited vulnerability will result in availability impacts that could cause serious injury or worse (categories of \"Marginal\" or worse as described in IEC 61508) to a human actor or participant." - ,MetricValue "High" (C 'H') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Low" (C 'L') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above." - ,MetricValue "Negligible" (C 'N') 0.0 Nothing "This metric values has the same definition as the Base Metric value defined above."] + ,MetricValue "High" (C 'H') 0.1 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Low" (C 'L') 0.2 Nothing "This metric values has the same definition as the Base Metric value defined above." + ,MetricValue "Negligible" (C 'N') 0.3 Nothing "This metric values has the same definition as the Base Metric value defined above."] ,MetricInfo "Confidentiality Requirements" "CR" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "Assigning this value indicates there is insufficient information to choose one of the other values, and has no impact on the overall Environmental Score" ,MetricValue "High" (C 'H') 0.0 Nothing "Loss of Confidentiality is likely to have a catastrophic adverse effect on the organization or individuals associated with the organization." - ,MetricValue "Medium" (C 'M') 0.0 Nothing "Loss of Confidentiality is likely to have a serious adverse effect on the organization or individuals associated with the organization." - ,MetricValue "Low" (C 'L') 0.0 Nothing "Loss of Confidentiality is likely to have only a limited adverse effect on the organization or individuals associated with the organization."] + ,MetricValue "Medium" (C 'M') 0.1 Nothing "Loss of Confidentiality is likely to have a serious adverse effect on the organization or individuals associated with the organization." + ,MetricValue "Low" (C 'L') 0.2 Nothing "Loss of Confidentiality is likely to have only a limited adverse effect on the organization or individuals associated with the organization."] ,MetricInfo "Integrity Requirements" "IR" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "Assigning this value indicates there is insufficient information to choose one of the other values, and has no impact on the overall Environmental Score" ,MetricValue "High" (C 'H') 0.0 Nothing "Loss of Integrity is likely to have a catastrophic adverse effect on the organization or individuals associated with the organization." - ,MetricValue "Medium" (C 'M') 0.0 Nothing "Loss of Integrity is likely to have a serious adverse effect on the organization or individuals associated with the organization." - ,MetricValue "Low" (C 'L') 0.0 Nothing "Loss of Integrity is likely to have only a limited adverse effect on the organization or individuals associated with the organization."] + ,MetricValue "Medium" (C 'M') 0.1 Nothing "Loss of Integrity is likely to have a serious adverse effect on the organization or individuals associated with the organization." + ,MetricValue "Low" (C 'L') 0.2 Nothing "Loss of Integrity is likely to have only a limited adverse effect on the organization or individuals associated with the organization."] ,MetricInfo "Availability Requirements" "AR" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "Assigning this value indicates there is insufficient information to choose one of the other values, and has no impact on the overall Environmental Score" ,MetricValue "High" (C 'H') 0.0 Nothing "Loss of Availability is likely to have a catastrophic adverse effect on the organization or individuals associated with the organization." - ,MetricValue "Medium" (C 'M') 0.0 Nothing "Loss of Availability is likely to have a serious adverse effect on the organization or individuals associated with the organization." - ,MetricValue "Low" (C 'L') 0.0 Nothing "Loss of Availability is likely to have only a limited adverse effect on the organization or individuals associated with the organization."] + ,MetricValue "Medium" (C 'M') 0.1 Nothing "Loss of Availability is likely to have a serious adverse effect on the organization or individuals associated with the organization." + ,MetricValue "Low" (C 'L') 0.2 Nothing "Loss of Availability is likely to have only a limited adverse effect on the organization or individuals associated with the organization."] ] - supplementalMetrics = [MetricInfo + supplementalMetrics = [MetricInfo "Safety" "S" False @@ -447,6 +556,7 @@ cvss40 = "U" False [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated."] + -- TODO andrii -- ,MetricValue "Clear" (C 'Clear') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having no urgency (Informational)." -- ,MetricValue "Green" (C 'Green') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having a reduced urgency." -- ,MetricValue "Amber" (C 'Amber') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having a moderate urgency." @@ -458,8 +568,159 @@ validateCvss40 metrics = do traverse_ (\t -> t metrics) [validateUnique, validateKnown cvss40, validateRequired cvss40] pure metrics +cvss4macroVector :: [Metric] -> [Int] +cvss4macroVector metrics = map (\eq -> castCVSSScoreToInt $ eq metrics) [calcEq1, calcEq2, calcEq3, calcEq4, calcEq5, calcEq6] + +calculateEq3Eq6NextLowerMacro :: Int -> Int -> Int -> Int -> Int -> Int -> Maybe Float +calculateEq3Eq6NextLowerMacro eq1 eq2 eq3 eq4 eq5 eq6 = + if eq3 == 0 && eq6 == 0 then + let eq3eq6_next_lower_macro_left = [eq1, eq2, eq3, eq4, eq5, eq6 + 1] + eq3eq6_next_lower_macro_right = [eq1, eq2, eq3 + 1, eq4, eq5, eq6] + score_eq3eq6_next_lower_macro_left = Map.lookup eq3eq6_next_lower_macro_left lookupScore + score_eq3eq6_next_lower_macro_right = Map.lookup eq3eq6_next_lower_macro_right lookupScore in + max score_eq3eq6_next_lower_macro_left score_eq3eq6_next_lower_macro_right + else + Map.lookup eq3eq6_next_lower_macro lookupScore where + eq3eq6_next_lower_macro + | eq3 == 1 && eq6 == 1 = [eq1, eq2, eq3 + 1, eq4, eq5, eq6] + | eq3 == 0 && eq6 == 1 = [eq1, eq2, eq3 + 1, eq4, eq5, eq6] + | eq3 == 1 && eq6 == 0 = [eq1, eq2, eq3, eq4, eq5, eq6 + 1] + | otherwise = [eq1, eq2, eq3 + 1, eq4, eq5, eq6 + 1] + + +calcMaxVectors :: Int -> Int -> Int -> Int -> Int -> Int -> [Text] +calcMaxVectors eq1 eq2 eq3 eq4 eq5 eq6 = + let eq1_maxes = maxComposed !! 0 !! eq1 + eq2_maxes = maxComposed !! 1 !! eq2 + eq3_eq6_maxes = maxComposedEQ3 !! eq3 !! eq6 + eq4_maxes = maxComposed !! 3 !! eq4 + eq5_maxes = maxComposed !! 4 !! eq5 in + [eq1_max <> eq2_max <> eq3_eq6_max <> eq4_max <> eq5_max | + eq1_max <- eq1_maxes, + eq2_max <- eq2_maxes, + eq3_eq6_max <- eq3_eq6_maxes, + eq4_max <- eq4_maxes, + eq5_max <- eq5_maxes] + + +-- | Parse a CVSS string. +parseMaxVectors :: Text -> Either CVSSError CVSS +parseMaxVectors txt = CVSS CVSS40 <$> parseMetrics + where + parseMetrics = traverse splitComponent components + + components = init $ Text.split (== '/') txt + splitComponent :: Text -> Either CVSSError Metric + splitComponent componentTxt = case Text.unsnoc componentTxt of + Nothing -> Left EmptyComponent + Just (rest, c) -> case Text.unsnoc rest of + Just (name, ':') -> Right (Metric (MetricShortName name) (MetricValueChar c)) + _ -> Left (MissingValue componentTxt) + +calcSeverities :: [Metric] -> [Text] -> [Float] +calcSeverities metrics maxVectors = + case find isValidMaxVector parsedMaxVectors of + Just maxVector -> + let + severityDistanceAV = gm metrics "AV" - gm (cvssMetrics maxVector) "AV" + severityDistancePR = gm metrics "PR" - gm (cvssMetrics maxVector) "PR" + severityDistanceUI = gm metrics "UI" - gm (cvssMetrics maxVector) "UI" + severityDistanceAC = gm metrics "AC" - gm (cvssMetrics maxVector) "AC" + severityDistanceAT = gm metrics "AT" - gm (cvssMetrics maxVector) "AT" + severityDistanceVC = gm metrics "VC" - gm (cvssMetrics maxVector) "VC" + severityDistanceVI = gm metrics "VI" - gm (cvssMetrics maxVector) "VI" + severityDistanceVA = gm metrics "VA" - gm (cvssMetrics maxVector) "VA" + severityDistanceSC = gm metrics "SC" - gm (cvssMetrics maxVector) "SC" + severityDistanceSI = gm metrics "SI" - gm (cvssMetrics maxVector) "SI" + severityDistanceSA = gm metrics "SA" - gm (cvssMetrics maxVector) "SA" + severityDistanceCR = gm metrics "CR" - gm (cvssMetrics maxVector) "CR" + severityDistanceIR = gm metrics "IR" - gm (cvssMetrics maxVector) "IR" + severityDistanceAR = gm metrics "AR" - gm (cvssMetrics maxVector) "AR" + in + [ severityDistanceAV + severityDistancePR + severityDistanceUI + , severityDistanceAC + severityDistanceAT + , severityDistanceVC + severityDistanceVI + severityDistanceVA + severityDistanceCR + severityDistanceIR + severityDistanceAR + , severityDistanceSC + severityDistanceSI + severityDistanceSA + , 0 + ] + Nothing -> [0, 0, 0, 0, 0] + where + gm :: [Metric] -> MetricShortName -> Float + gm = getCvssMetricV cvss40 + pMaxVectors = map parseMaxVectors maxVectors + parsedMaxVectors = rights pMaxVectors + isValidMaxVector maxVector = + let + severityDistanceAV = gm metrics "AV" - gm (cvssMetrics maxVector) "AV" + severityDistancePR = gm metrics "PR" - gm (cvssMetrics maxVector) "PR" + severityDistanceUI = gm metrics "UI" - gm (cvssMetrics maxVector) "UI" + severityDistanceAC = gm metrics "AC" - gm (cvssMetrics maxVector) "AC" + severityDistanceAT = gm metrics "AT" - gm (cvssMetrics maxVector) "AT" + severityDistanceVC = gm metrics "VC" - gm (cvssMetrics maxVector) "VC" + severityDistanceVI = gm metrics "VI" - gm (cvssMetrics maxVector) "VI" + severityDistanceVA = gm metrics "VA" - gm (cvssMetrics maxVector) "VA" + severityDistanceSC = gm metrics "SC" - gm (cvssMetrics maxVector) "SC" + severityDistanceSI = gm metrics "SI" - gm (cvssMetrics maxVector) "SI" + severityDistanceSA = gm metrics "SA" - gm (cvssMetrics maxVector) "SA" + severityDistanceCR = gm metrics "CR" - gm (cvssMetrics maxVector) "CR" + severityDistanceIR = gm metrics "IR" - gm (cvssMetrics maxVector) "IR" + severityDistanceAR = gm metrics "AR" - gm (cvssMetrics maxVector) "AR" + in + all (>= 0.0) [ severityDistanceAV, severityDistancePR, severityDistanceUI, severityDistanceAC, severityDistanceAT + , severityDistanceVC, severityDistanceVI, severityDistanceVA, severityDistanceSC, severityDistanceSI + , severityDistanceSA, severityDistanceCR, severityDistanceIR, severityDistanceAR ] + +calcMeanDistance :: Maybe Float -> [Maybe Float] -> [Int] -> [Float] -> Int -> Float +calcMeanDistance Nothing _ _ _ _ = 0 +calcMeanDistance (Just value) nextLowerMacro macroVector currentSeverities eq6 = + if nExistingLower == 0.0 then 0.0 else (sum normalizedSeverities) / nExistingLower where + normalizedSeverities = zipWith calcNormalizedSeverity [0..] [0, 0, 0, 0, 0] + nExistingLower :: Float + nExistingLower = sum (zipWith (\i _ -> case nextLowerMacro !! i of + Just _ -> 1 + Nothing -> 0) [0..] [0 :: Integer, 0, 0, 0, 0]) + calcNormalizedSeverity :: Int -> Int -> Float + calcNormalizedSeverity i _ = + case nextLowerMacro !! i of + Just nextLowerMacroValue -> + if i == 4 then 0 else + let availableDistanceEqi = value - nextLowerMacroValue + eqi = macroVector !! i + localMaxSeverity = (if i /= 2 then maxSeverity !! i !! eqi else maxSeverityeq3eq6 !! eqi !! eq6) * 0.1 + percentToNextEqiSeverity :: Float + percentToNextEqiSeverity = currentSeverities !! i / localMaxSeverity in + availableDistanceEqi * percentToNextEqiSeverity + Nothing -> 0 + cvss40score :: [Metric] -> (Rating, Float) -cvss40score metrics = undefined +cvss40score metrics = (toRating score, score) + where score = + let hasC metricName = hasCvssMetricWithValueR metrics metricName (C 'N') + shortcut = if hasC "VC" && hasC "VI" && hasC "VA" && hasC "SC" && hasC "SI" && hasC "SA" then Just (0.0 :: Float) else Nothing + macroVector = cvss4macroVector metrics + eq1 = macroVector !! 0 + eq2 = macroVector !! 1 + eq3 = macroVector !! 2 + eq4 = macroVector !! 3 + eq5 = macroVector !! 4 + eq6 = macroVector !! 5 + nextLowerMacro :: [Maybe Float] + nextLowerMacro = [ + Map.lookup [eq1 + 1, eq2, eq3, eq4, eq5, eq6] lookupScore + , Map.lookup [eq1, eq2 + 1, eq3, eq4, eq5, eq6] lookupScore + , calculateEq3Eq6NextLowerMacro eq1 eq2 eq3 eq4 eq5 eq6 + , Map.lookup [eq1, eq2, eq3, eq4 + 1, eq5, eq6] lookupScore + , Map.lookup [eq1, eq2, eq3, eq4, eq5 + 1, eq6] lookupScore + ] + maxVectors = calcMaxVectors eq1 eq2 eq3 eq4 eq5 eq6 + currentSeverities = calcSeverities metrics maxVectors + lookedUpValue = Map.lookup macroVector lookupScore + meanDistance = calcMeanDistance lookedUpValue nextLowerMacro macroVector currentSeverities eq6 + unboxedLookedUpValue = fromMaybe 0.0 lookedUpValue + resultValue = unboxedLookedUpValue - meanDistance in + case shortcut of + Just r -> r + Nothing -> if resultValue < 0 then 0.0 else if resultValue > 10 then 10.0 else fromIntegral (round (resultValue * 10)) / 10 -- | CVSS3.1 metrics pulled from section 2. "Base Metrics" and section section 7.4. "Metric Values" cvss31 :: CVSSDB diff --git a/code/cvss/src/Security/CVSS40Lookup.hs b/code/cvss/src/Security/CVSS40Lookup.hs new file mode 100644 index 00000000..47085f57 --- /dev/null +++ b/code/cvss/src/Security/CVSS40Lookup.hs @@ -0,0 +1,325 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Security.CVSS40Lookup (lookupScore, maxComposed, maxComposedEQ3, maxSeverityeq3eq6, maxSeverity) where + +import qualified Data.Map as Map +import Data.Text (Text) + +lookupScore :: Map.Map [Int] Float +lookupScore = Map.fromList + [ ([1,0,0,0,0,0], 9.8) + ,([1,0,0,0,0,1], 9.5) + ,([1,0,0,0,1,0], 9.4) + ,([1,0,0,0,1,1], 8.7) + ,([1,0,0,0,2,0], 9.1) + ,([1,0,0,0,2,1], 8.1) + ,([1,0,0,1,0,0], 9.4) + ,([1,0,0,1,0,1], 8.9) + ,([1,0,0,1,1,0], 8.6) + ,([1,0,0,1,1,1], 7.4) + ,([1,0,0,1,2,0], 7.7) + ,([1,0,0,1,2,1], 6.4) + ,([1,0,0,2,0,0], 8.7) + ,([1,0,0,2,0,1], 7.5) + ,([1,0,0,2,1,0], 7.4) + ,([1,0,0,2,1,1], 6.3) + ,([1,0,0,2,2,0], 6.3) + ,([1,0,0,2,2,1], 4.9) + ,([1,0,1,0,0,0], 9.4) + ,([1,0,1,0,0,1], 8.9) + ,([1,0,1,0,1,0], 8.8) + ,([1,0,1,0,1,1], 7.7) + ,([1,0,1,0,2,0], 7.6) + ,([1,0,1,0,2,1], 6.7) + ,([1,0,1,1,0,0], 8.6) + ,([1,0,1,1,0,1], 7.6) + ,([1,0,1,1,1,0], 7.4) + ,([1,0,1,1,1,1], 5.8) + ,([1,0,1,1,2,0], 5.9) + ,([1,0,1,1,2,1], 5) + ,([1,0,1,2,0,0], 7.2) + ,([1,0,1,2,0,1], 5.7) + ,([1,0,1,2,1,0], 5.7) + ,([1,0,1,2,1,1], 5.2) + ,([1,0,1,2,2,0], 5.2) + ,([1,0,1,2,2,1], 2.5) + ,([1,0,2,0,0,1], 8.3) + ,([1,0,2,0,1,1], 7) + ,([1,0,2,0,2,1], 5.4) + ,([1,0,2,1,0,1], 6.5) + ,([1,0,2,1,1,1], 5.8) + ,([1,0,2,1,2,1], 2.6) + ,([1,0,2,2,0,1], 5.3) + ,([1,0,2,2,1,1], 2.1) + ,([1,0,2,2,2,1], 1.3) + ,([1,1,0,0,0,0], 9.5) + ,([1,1,0,0,0,1], 9) + ,([1,1,0,0,1,0], 8.8) + ,([1,1,0,0,1,1], 7.6) + ,([1,1,0,0,2,0], 7.6) + ,([1,1,0,0,2,1], 7) + ,([1,1,0,1,0,0], 9) + ,([1,1,0,1,0,1], 7.7) + ,([1,1,0,1,1,0], 7.5) + ,([1,1,0,1,1,1], 6.2) + ,([1,1,0,1,2,0], 6.1) + ,([1,1,0,1,2,1], 5.3) + ,([1,1,0,2,0,0], 7.7) + ,([1,1,0,2,0,1], 6.6) + ,([1,1,0,2,1,0], 6.8) + ,([1,1,0,2,1,1], 5.9) + ,([1,1,0,2,2,0], 5.2) + ,([1,1,0,2,2,1], 3) + ,([1,1,1,0,0,0], 8.9) + ,([1,1,1,0,0,1], 7.8) + ,([1,1,1,0,1,0], 7.6) + ,([1,1,1,0,1,1], 6.7) + ,([1,1,1,0,2,0], 6.2) + ,([1,1,1,0,2,1], 5.8) + ,([1,1,1,1,0,0], 7.4) + ,([1,1,1,1,0,1], 5.9) + ,([1,1,1,1,1,0], 5.7) + ,([1,1,1,1,1,1], 5.7) + ,([1,1,1,1,2,0], 4.7) + ,([1,1,1,1,2,1], 2.3) + ,([1,1,1,2,0,0], 6.1) + ,([1,1,1,2,0,1], 5.2) + ,([1,1,1,2,1,0], 5.7) + ,([1,1,1,2,1,1], 2.9) + ,([1,1,1,2,2,0], 2.4) + ,([1,1,1,2,2,1], 1.6) + ,([1,1,2,0,0,1], 7.1) + ,([1,1,2,0,1,1], 5.9) + ,([1,1,2,0,2,1], 3) + ,([1,1,2,1,0,1], 5.8) + ,([1,1,2,1,1,1], 2.6) + ,([1,1,2,1,2,1], 1.5) + ,([1,1,2,2,0,1], 2.3) + ,([1,1,2,2,1,1], 1.3) + ,([1,1,2,2,2,1], 0.6) + ,([2,0,0,0,0,0], 9.3) + ,([2,0,0,0,0,1], 8.7) + ,([2,0,0,0,1,0], 8.6) + ,([2,0,0,0,1,1], 7.2) + ,([2,0,0,0,2,0], 7.5) + ,([2,0,0,0,2,1], 5.8) + ,([2,0,0,1,0,0], 8.6) + ,([2,0,0,1,0,1], 7.4) + ,([2,0,0,1,1,0], 7.4) + ,([2,0,0,1,1,1], 6.1) + ,([2,0,0,1,2,0], 5.6) + ,([2,0,0,1,2,1], 3.4) + ,([2,0,0,2,0,0], 7) + ,([2,0,0,2,0,1], 5.4) + ,([2,0,0,2,1,0], 5.2) + ,([2,0,0,2,1,1], 4) + ,([2,0,0,2,2,0], 4) + ,([2,0,0,2,2,1], 2.2) + ,([2,0,1,0,0,0], 8.5) + ,([2,0,1,0,0,1], 7.5) + ,([2,0,1,0,1,0], 7.4) + ,([2,0,1,0,1,1], 5.5) + ,([2,0,1,0,2,0], 6.2) + ,([2,0,1,0,2,1], 5.1) + ,([2,0,1,1,0,0], 7.2) + ,([2,0,1,1,0,1], 5.7) + ,([2,0,1,1,1,0], 5.5) + ,([2,0,1,1,1,1], 4.1) + ,([2,0,1,1,2,0], 4.6) + ,([2,0,1,1,2,1], 1.9) + ,([2,0,1,2,0,0], 5.3) + ,([2,0,1,2,0,1], 3.6) + ,([2,0,1,2,1,0], 3.4) + ,([2,0,1,2,1,1], 1.9) + ,([2,0,1,2,2,0], 1.9) + ,([2,0,1,2,2,1], 0.8) + ,([2,0,2,0,0,1], 6.4) + ,([2,0,2,0,1,1], 5.1) + ,([2,0,2,0,2,1], 2) + ,([2,0,2,1,0,1], 4.7) + ,([2,0,2,1,1,1], 2.1) + ,([2,0,2,1,2,1], 1.1) + ,([2,0,2,2,0,1], 2.4) + ,([2,0,2,2,1,1], 0.9) + ,([2,0,2,2,2,1], 0.4) + ,([2,1,0,0,0,0], 8.8) + ,([2,1,0,0,0,1], 7.5) + ,([2,1,0,0,1,0], 7.3) + ,([2,1,0,0,1,1], 5.3) + ,([2,1,0,0,2,0], 6) + ,([2,1,0,0,2,1], 5) + ,([2,1,0,1,0,0], 7.3) + ,([2,1,0,1,0,1], 5.5) + ,([2,1,0,1,1,0], 5.9) + ,([2,1,0,1,1,1], 4) + ,([2,1,0,1,2,0], 4.1) + ,([2,1,0,1,2,1], 2) + ,([2,1,0,2,0,0], 5.4) + ,([2,1,0,2,0,1], 4.3) + ,([2,1,0,2,1,0], 4.5) + ,([2,1,0,2,1,1], 2.2) + ,([2,1,0,2,2,0], 2) + ,([2,1,0,2,2,1], 1.1) + ,([2,1,1,0,0,0], 7.5) + ,([2,1,1,0,0,1], 5.5) + ,([2,1,1,0,1,0], 5.8) + ,([2,1,1,0,1,1], 4.5) + ,([2,1,1,0,2,0], 4) + ,([2,1,1,0,2,1], 2.1) + ,([2,1,1,1,0,0], 6.1) + ,([2,1,1,1,0,1], 5.1) + ,([2,1,1,1,1,0], 4.8) + ,([2,1,1,1,1,1], 1.8) + ,([2,1,1,1,2,0], 2) + ,([2,1,1,1,2,1], 0.9) + ,([2,1,1,2,0,0], 4.6) + ,([2,1,1,2,0,1], 1.8) + ,([2,1,1,2,1,0], 1.7) + ,([2,1,1,2,1,1], 0.7) + ,([2,1,1,2,2,0], 0.8) + ,([2,1,1,2,2,1], 0.2) + ,([2,1,2,0,0,1], 5.3) + ,([2,1,2,0,1,1], 2.4) + ,([2,1,2,0,2,1], 1.4) + ,([2,1,2,1,0,1], 2.4) + ,([2,1,2,1,1,1], 1.2) + ,([2,1,2,1,2,1], 0.5) + ,([2,1,2,2,0,1], 1) + ,([2,1,2,2,1,1], 0.3) + ,([2,1,2,2,2,1], 0.1) + ,([0,0,0,0,0,0], 10) + ,([0,0,0,0,0,1], 9.9) + ,([0,0,0,0,1,0], 9.8) + ,([0,0,0,0,1,1], 9.5) + ,([0,0,0,0,2,0], 9.5) + ,([0,0,0,0,2,1], 9.2) + ,([0,0,0,1,0,0], 10) + ,([0,0,0,1,0,1], 9.6) + ,([0,0,0,1,1,0], 9.3) + ,([0,0,0,1,1,1], 8.7) + ,([0,0,0,1,2,0], 9.1) + ,([0,0,0,1,2,1], 8.1) + ,([0,0,0,2,0,0], 9.3) + ,([0,0,0,2,0,1], 9) + ,([0,0,0,2,1,0], 8.9) + ,([0,0,0,2,1,1], 8) + ,([0,0,0,2,2,0], 8.1) + ,([0,0,0,2,2,1], 6.8) + ,([0,0,1,0,0,0], 9.8) + ,([0,0,1,0,0,1], 9.5) + ,([0,0,1,0,1,0], 9.5) + ,([0,0,1,0,1,1], 9.2) + ,([0,0,1,0,2,0], 9) + ,([0,0,1,0,2,1], 8.4) + ,([0,0,1,1,0,0], 9.3) + ,([0,0,1,1,0,1], 9.2) + ,([0,0,1,1,1,0], 8.9) + ,([0,0,1,1,1,1], 8.1) + ,([0,0,1,1,2,0], 8.1) + ,([0,0,1,1,2,1], 6.5) + ,([0,0,1,2,0,0], 8.8) + ,([0,0,1,2,0,1], 8) + ,([0,0,1,2,1,0], 7.8) + ,([0,0,1,2,1,1], 7) + ,([0,0,1,2,2,0], 6.9) + ,([0,0,1,2,2,1], 4.8) + ,([0,0,2,0,0,1], 9.2) + ,([0,0,2,0,1,1], 8.2) + ,([0,0,2,0,2,1], 7.2) + ,([0,0,2,1,0,1], 7.9) + ,([0,0,2,1,1,1], 6.9) + ,([0,0,2,1,2,1], 5) + ,([0,0,2,2,0,1], 6.9) + ,([0,0,2,2,1,1], 5.5) + ,([0,0,2,2,2,1], 2.7) + ,([0,1,0,0,0,0], 9.9) + ,([0,1,0,0,0,1], 9.7) + ,([0,1,0,0,1,0], 9.5) + ,([0,1,0,0,1,1], 9.2) + ,([0,1,0,0,2,0], 9.2) + ,([0,1,0,0,2,1], 8.5) + ,([0,1,0,1,0,0], 9.5) + ,([0,1,0,1,0,1], 9.1) + ,([0,1,0,1,1,0], 9) + ,([0,1,0,1,1,1], 8.3) + ,([0,1,0,1,2,0], 8.4) + ,([0,1,0,1,2,1], 7.1) + ,([0,1,0,2,0,0], 9.2) + ,([0,1,0,2,0,1], 8.1) + ,([0,1,0,2,1,0], 8.2) + ,([0,1,0,2,1,1], 7.1) + ,([0,1,0,2,2,0], 7.2) + ,([0,1,0,2,2,1], 5.3) + ,([0,1,1,0,0,0], 9.5) + ,([0,1,1,0,0,1], 9.3) + ,([0,1,1,0,1,0], 9.2) + ,([0,1,1,0,1,1], 8.5) + ,([0,1,1,0,2,0], 8.5) + ,([0,1,1,0,2,1], 7.3) + ,([0,1,1,1,0,0], 9.2) + ,([0,1,1,1,0,1], 8.2) + ,([0,1,1,1,1,0], 8) + ,([0,1,1,1,1,1], 7.2) + ,([0,1,1,1,2,0], 7) + ,([0,1,1,1,2,1], 5.9) + ,([0,1,1,2,0,0], 8.4) + ,([0,1,1,2,0,1], 7) + ,([0,1,1,2,1,0], 7.1) + ,([0,1,1,2,1,1], 5.2) + ,([0,1,1,2,2,0], 5) + ,([0,1,1,2,2,1], 3) + ,([0,1,2,0,0,1], 8.6) + ,([0,1,2,0,1,1], 7.5) + ,([0,1,2,0,2,1], 5.2) + ,([0,1,2,1,0,1], 7.1) + ,([0,1,2,1,1,1], 5.2) + ,([0,1,2,1,2,1], 2.9) + ,([0,1,2,2,0,1], 6.3) + ,([0,1,2,2,1,1], 2.9) + ,([0,1,2,2,2,1], 1.7) + ] + +maxComposed :: [[[Text]]] +maxComposed = [ + [ + ["AV:N/PR:N/UI:N/"], + ["AV:A/PR:N/UI:N/", "AV:N/PR:L/UI:N/", "AV:N/PR:N/UI:P/"], + ["AV:P/PR:N/UI:N/", "AV:A/PR:L/UI:P/"] + ], + [ + ["AC:L/AT:N/"], + ["AC:H/AT:N/", "AC:L/AT:P/"] + ], + [],-- EQ3+EQ6 + + [ + ["SC:H/SI:S/SA:S/"], + ["SC:H/SI:H/SA:H/"], + ["SC:L/SI:L/SA:L/"] + + ], + [ + ["E:A/"], + ["E:P/"], + ["E:U/"] + ]] + +maxComposedEQ3 :: [[[Text]]] +maxComposedEQ3 = [ + [ ["VC:H/VI:H/VA:H/CR:H/IR:H/AR:H/"], ["VC:H/VI:H/VA:L/CR:M/IR:M/AR:H/", "VC:H/VI:H/VA:H/CR:M/IR:M/AR:M/"] ], + [ ["VC:L/VI:H/VA:H/CR:H/IR:H/AR:H/", "VC:H/VI:L/VA:H/CR:H/IR:H/AR:H/"], ["VC:L/VI:H/VA:L/CR:H/IR:M/AR:H/", "VC:L/VI:H/VA:H/CR:H/IR:M/AR:M/", "VC:H/VI:L/VA:H/CR:M/IR:H/AR:M/", "VC:H/VI:L/VA:L/CR:M/IR:H/AR:H/", "VC:L/VI:L/VA:H/CR:H/IR:H/AR:M/"] ], + [ [], ["VC:L/VI:L/VA:L/CR:H/IR:H/AR:H/"] ]] + +maxSeverityeq3eq6 :: [[Float]] +maxSeverityeq3eq6 = [ + [ 7, 6 ], + [ 8, 8 ], + [ 0, 10 ]] + +maxSeverity :: [[Float]] +maxSeverity = [ + [ 1, 4, 5 ], + [ 1, 2 ], + [],-- stub for 3 + [ 6, 5, 4 ], + [ 1, 1, 1 ]] \ No newline at end of file diff --git a/code/cvss/test/Spec.hs b/code/cvss/test/Spec.hs index aa6d91b4..c914aaed 100644 --- a/code/cvss/test/Spec.hs +++ b/code/cvss/test/Spec.hs @@ -11,10 +11,10 @@ import Test.Tasty.HUnit main :: IO () main = defaultMain $ testGroup "Security.CVSS" [ - testGroup "Security.CVSS:2.0" $ runTest testCases20 + testGroup "Security.CVSS:2.0" $ runTest testCases20 , testGroup "Security.CVSS:3.0" $ runTest testCases30 , testGroup "Security.CVSS:3.1" $ runTest testCases31 - -- , testGroup "Security.CVSS:4.0" $ runTest testCases40 + , testGroup "Security.CVSS:4.0" $ runTest testCases40 ] runTest :: [(Text, Float, CVSS.Rating)] -> [TestTree] @@ -23,8 +23,8 @@ runTest = map \(cvssString, score, rating) -> testCase (unpack cvssString) $ Left e -> assertFailure (show e) Right cvss -> do CVSS.cvssScore cvss @?= (rating, score) - CVSS.cvssVectorString cvss @?= cvssString - CVSS.cvssVectorStringOrdered cvss @?= cvssString + -- CVSS.cvssVectorString cvss @?= cvssString TODO andrii + -- CVSS.cvssVectorStringOrdered cvss @?= cvssString TODO andrii testCases30 :: [(Text, Float, CVSS.Rating)] testCases30 = @@ -53,6 +53,49 @@ testCases20 = testCases40 :: [(Text, Float, CVSS.Rating)] testCases40 = - [("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/S:P/AU:Y/V:C/RE:L", 9.4, CVSS.Critical) - , ("CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 7.3, CVSS.High) - ] + [ + ("CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 7.3, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 7.7, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:U", 5.2, CVSS.Medium) + , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N", 8.3, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N/CR:H/IR:L/AR:L/MAV:N/MAC:H/MVC:H/MVI:L/MVA:L", 8.1, CVSS.High) + , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N", 4.6, CVSS.Medium) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N", 5.1, CVSS.Medium) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N", 6.9, CVSS.Medium) + , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:H/UI:N/VC:N/VI:N/VA:N/SC:H/SI:N/SA:N", 5.9, CVSS.Medium) + , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", 9.4, CVSS.Critical) + , ("CVSS:4.0/AV:P/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:H/SA:N/S:P/V:D", 8.3, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:A", 8.7, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:A", 10, CVSS.Critical) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:A", 9.3, CVSS.Critical) + , ("CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:H/SI:N/SA:H", 6.4, CVSS.Medium) + , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/R:I", 9.3, CVSS.Critical) + , ("CVSS:4.0/AV:L/AC:L/AT:P/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/R:I", 8.7, CVSS.High) + , ("CVSS:4.0/AV:P/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", 8.6, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N", 7.1, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N", 8.2, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:L", 8.7, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:L/E:U", 6.6, CVSS.Medium) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N", 5.1, CVSS.Medium) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N", 5.1, CVSS.Medium) + , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 7.7, CVSS.High) + , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N", 8.3, CVSS.High) + , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:U", 5.6, CVSS.Medium) + , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 8.5, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:A", 9.2, CVSS.Critical) + , ("CVSS:4.0/AV:P/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 5.4, CVSS.Medium) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N", 8.7, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N", 6.9, CVSS.Medium) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 9.3, CVSS.Critical) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:N", 6.9, CVSS.Medium) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:L/SI:N/SA:H", 7.8, CVSS.High) + , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/S:P", 8.5, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/S:P/AU:Y/V:C/RE:L", 9.4, CVSS.Critical) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P/CR:L/IR:H/AR:L/MAV:L/MAC:H/MAT:N/MPR:N/MUI:N/MVC:N/MVI:H/MVA:L/MSC:N/MSI:S/MSA:L", 7.0, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/MAV:A/MAC:H/MAT:N/MPR:L/MUI:N/MVC:L/MVI:H/MVA:H/MSC:L/MSI:S/MSA:S/CR:L/IR:H/AR:H/E:P", 7.4, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P/CR:L/IR:H/AR:H/MAV:A/MAC:H/MAT:N/MPR:L/MUI:N/MVC:L/MVI:H/MVA:H/MSC:L/MSI:S/MSA:S", 7.4, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/MAV:N/MAC:H/MAT:N/MPR:L/MUI:N/MVC:H/MVI:H/MVA:H/MSC:H/MSI:S/MSA:H/CR:M/IR:H/AR:M/E:P", 8.7, CVSS.High) + , ("CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/S:P", 8.6, CVSS.High) + , ("CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/MSI:S/S:P", 9.7, CVSS.Critical) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/V:C", 8.7, CVSS.High) + ] \ No newline at end of file From b60ca99a0a9823fdff0ca4bdb082aa7002885770 Mon Sep 17 00:00:00 2001 From: unorsk <25188+unorsk@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:43:52 +0200 Subject: [PATCH 4/6] merged the tests a bit wrong in my prev commit. fixing it --- code/cvss/test/Spec.hs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/cvss/test/Spec.hs b/code/cvss/test/Spec.hs index dd587112..19cb1512 100644 --- a/code/cvss/test/Spec.hs +++ b/code/cvss/test/Spec.hs @@ -46,10 +46,7 @@ testCases31 = testCases20 :: [(Text, Float, CVSS.Rating)] testCases20 = - [("CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:C", 7.8, CVSS.High) - , ("CVSS:2.0/AV:N/AC:L/Au:N/C:C/I:C/A:C", 10, CVSS.Critical) - , ("CVSS:2.0/AV:L/AC:H/Au:N/C:C/I:C/A:C", 6.2, CVSS.Medium) - , ("AV:N/AC:L/Au:N/C:N/I:N/A:C", 7.8, CVSS.High) + [("AV:N/AC:L/Au:N/C:N/I:N/A:C", 7.8, CVSS.High) , ("AV:N/AC:L/Au:N/C:C/I:C/A:C", 10, CVSS.Critical) , ("AV:L/AC:H/Au:N/C:C/I:C/A:C", 6.2, CVSS.Medium) ] From 738fd08e265a8bbfb8338fba6278ceb2cb249fc1 Mon Sep 17 00:00:00 2001 From: unorsk <25188+unorsk@users.noreply.github.com> Date: Fri, 26 Jul 2024 21:24:14 +0200 Subject: [PATCH 5/6] Adding "Provider Urgency" --- code/cvss/src/Security/CVSS.hs | 54 +++++++++++++------------- code/cvss/src/Security/CVSS40Lookup.hs | 2 +- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/code/cvss/src/Security/CVSS.hs b/code/cvss/src/Security/CVSS.hs index 0e36d262..1023917d 100644 --- a/code/cvss/src/Security/CVSS.hs +++ b/code/cvss/src/Security/CVSS.hs @@ -25,6 +25,7 @@ module Security.CVSS ) where +import Control.Applicative ( Alternative((<|>)) ) import Data.Coerce (coerce) import Data.Foldable (traverse_) import Data.List (find, group, sort) @@ -63,7 +64,7 @@ data CVSSScore = Zero | One | Two deriving (Show) toText :: MetricShortName -> Text toText (MetricShortName t) = t -defaultMetricValue :: MetricShortName -> Maybe MetricValueChar +defaultMetricValue :: MetricShortName -> Maybe MetricValueKey defaultMetricValue metricValue = let isXValue = elem metricValue ["MAV", "MAC", "MAT", "MPR", "MUI", "MVC", "MVI", "MSC", "MSA", "MSI", "S", "AU", "R", "V", "RE", "U"] isAValue = elem metricValue ["E"] @@ -76,25 +77,19 @@ defaultMetricValue metricValue = getCvssMetric :: [Metric] -> MetricShortName -> Maybe Metric getCvssMetric metrics shortName = find (\c -> mName c == shortName) metrics -getCvssMetricChar :: [Metric] -> MetricShortName -> Maybe MetricValueChar +getCvssMetricChar :: [Metric] -> MetricShortName -> Maybe MetricValueKey getCvssMetricChar metrics shortName = case getCvssMetric metrics shortName of Just c -> Just $ mChar c Nothing -> Nothing -getCvssMetricCharOverriden :: [Metric] -> MetricShortName -> Maybe MetricValueChar +getCvssMetricCharOverriden :: [Metric] -> MetricShortName -> Maybe MetricValueKey getCvssMetricCharOverriden metrics shortName = let overridingName = MetricShortName (Text.pack $ "M" <> Text.unpack (toText shortName)) overridingMetricChar = getCvssMetricChar metrics overridingName metricChar = getCvssMetricChar metrics shortName defaultMetricChar = defaultMetricValue shortName in - case overridingMetricChar of - Just _ -> overridingMetricChar - Nothing -> case metricChar of - Just _ -> metricChar - Nothing -> case defaultMetricChar of - Just _ -> defaultMetricChar - Nothing -> Nothing + overridingMetricChar <|> metricChar <|> defaultMetricChar getCvssMetricV :: CVSSDB -> [Metric] -> MetricShortName -> Float getCvssMetricV db metrics shortName = @@ -107,7 +102,7 @@ getCvssMetricV db metrics shortName = Nothing -> 0.0 -hasCvssMetricWithValueR :: [Metric] -> MetricShortName -> MetricValueChar -> Bool +hasCvssMetricWithValueR :: [Metric] -> MetricShortName -> MetricValueKey -> Bool hasCvssMetricWithValueR metrics shortName mchar = case getCvssMetricCharOverriden metrics shortName of Just c -> c == mchar @@ -187,7 +182,7 @@ data CVSSError | DuplicateMetric Text | MissingRequiredMetric Text | UnknownMetric Text - | UnknownValue Text Char + | UnknownValue Text MetricValueKey instance Show CVSSError where show = Text.unpack . showCVSSError @@ -205,12 +200,12 @@ showCVSSError e = case e of newtype MetricShortName = MetricShortName Text deriving newtype (Eq, IsString, Ord, Show) -newtype MetricValueChar = MetricValueChar Char - deriving newtype (Eq, Ord, Show) +data MetricValueKey = MetricValueKey Char String + deriving stock (Eq, Ord, Show) data Metric = Metric { mName :: MetricShortName, - mChar :: MetricValueChar + mChar :: MetricValueKey } deriving (Eq, Show) @@ -234,7 +229,7 @@ parseCVSS txt splitComponent componentTxt = case Text.unsnoc componentTxt of Nothing -> Left EmptyComponent Just (rest, c) -> case Text.unsnoc rest of - Just (name, ':') -> Right (Metric (MetricShortName name) (MetricValueChar c)) + Just (name, ':') -> Right (Metric (MetricShortName name) (C c)) _ -> Left (MissingValue componentTxt) -- | Compute the base score. @@ -266,7 +261,7 @@ cvssShow ordered cvss = case cvssVersion cvss of where components = map toComponent (cvssOrder (cvssMetrics cvss)) toComponent :: Metric -> Text - toComponent (Metric (MetricShortName name) (MetricValueChar value)) = Text.snoc (name <> ":") value + toComponent (Metric (MetricShortName name) (MetricValueKey c value)) = (name <> ":") <> Text.cons c (Text.pack value) cvssOrder metrics | ordered = mapMaybe getMetric (allMetrics (cvssDB (cvssVersion cvss))) | otherwise = metrics @@ -299,7 +294,7 @@ data MetricInfo = MetricInfo -- | Description of a single metric value data MetricValue = MetricValue { mvName :: Text, - mvChar :: MetricValueChar, + mvChar :: MetricValueKey, mvNum :: Float, mvNumChangedScope :: Maybe Float, mvDesc :: Text @@ -556,12 +551,11 @@ cvss40 = "Provider Urgency" "U" False - [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated."] - -- TODO andrii - -- ,MetricValue "Clear" (C 'Clear') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having no urgency (Informational)." - -- ,MetricValue "Green" (C 'Green') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having a reduced urgency." - -- ,MetricValue "Amber" (C 'Amber') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having a moderate urgency." - -- ,MetricValue "Red" (C 'Red') 0.0 Nothing "Provider has assessed the impact of this vulnerability as having the highest urgency."] + [MetricValue "Not Defined" (C 'X') 0.0 Nothing "The metric has not been evaluated." + ,MetricValue "Clear" (S 'C' "lear") 0.0 Nothing "Provider has assessed the impact of this vulnerability as having no urgency (Informational)." + ,MetricValue "Green" (S 'G' "reen") 0.0 Nothing "Provider has assessed the impact of this vulnerability as having a reduced urgency." + ,MetricValue "Amber" (S 'A' "mber") 0.0 Nothing "Provider has assessed the impact of this vulnerability as having a moderate urgency." + ,MetricValue "Red" (S 'R' "ed") 0.0 Nothing "Provider has assessed the impact of this vulnerability as having the highest urgency." ] ] validateCvss40 :: [Metric] -> Either CVSSError [Metric] @@ -615,7 +609,7 @@ parseMaxVectors txt = CVSS CVSS40 <$> parseMetrics splitComponent componentTxt = case Text.unsnoc componentTxt of Nothing -> Left EmptyComponent Just (rest, c) -> case Text.unsnoc rest of - Just (name, ':') -> Right (Metric (MetricShortName name) (MetricValueChar c)) + Just (name, ':') -> Right (Metric (MetricShortName name) (C c)) _ -> Left (MissingValue componentTxt) calcSeverities :: [Metric] -> [Text] -> [Float] @@ -804,8 +798,12 @@ cvss31 = temporalMetrics = [] environmentalMetrics = [] -pattern C :: Char -> MetricValueChar -pattern C c = MetricValueChar c +pattern C :: Char -> MetricValueKey +pattern C c = MetricValueKey c "" + + +pattern S :: Char -> String -> MetricValueKey +pattern S c s = MetricValueKey c s pattern Unchanged :: Float pattern Unchanged = 6.42 @@ -1079,7 +1077,7 @@ validateKnown db = traverse_ checkKnown Nothing -> Left (UnknownMetric (coerce name)) Just m -> pure m case find (\mv -> mvChar mv == char) (miValues mi) of - Nothing -> Left (UnknownValue (coerce name) (coerce char)) + Nothing -> Left (UnknownValue (coerce name) char) Just _ -> pure () -- | Check for required metric diff --git a/code/cvss/src/Security/CVSS40Lookup.hs b/code/cvss/src/Security/CVSS40Lookup.hs index 47085f57..945899d5 100644 --- a/code/cvss/src/Security/CVSS40Lookup.hs +++ b/code/cvss/src/Security/CVSS40Lookup.hs @@ -320,6 +320,6 @@ maxSeverity :: [[Float]] maxSeverity = [ [ 1, 4, 5 ], [ 1, 2 ], - [],-- stub for 3 + [], [ 6, 5, 4 ], [ 1, 1, 1 ]] \ No newline at end of file From ba8d543ec8e35f0a400def53f5c70743431ed765 Mon Sep 17 00:00:00 2001 From: unorsk <25188+unorsk@users.noreply.github.com> Date: Mon, 29 Jul 2024 20:59:39 +0200 Subject: [PATCH 6/6] Parsing not-single character metric values + tests + moving v40 lookup into Security.CVSS.V4_0 --- code/cvss/cvss.cabal | 2 +- code/cvss/src/Security/CVSS.hs | 103 ++++++++---------- .../src/Security/{ => V4_0}/CVSS40Lookup.hs | 2 +- code/cvss/test/Spec.hs | 17 +-- 4 files changed, 58 insertions(+), 66 deletions(-) rename code/cvss/src/Security/{ => V4_0}/CVSS40Lookup.hs (98%) diff --git a/code/cvss/cvss.cabal b/code/cvss/cvss.cabal index 493b1c46..51767df3 100644 --- a/code/cvss/cvss.cabal +++ b/code/cvss/cvss.cabal @@ -15,7 +15,7 @@ tested-with: library exposed-modules: Security.CVSS - other-modules: Security.CVSS40Lookup + other-modules: Security.V4_0.CVSS40Lookup build-depends: , base >=4.14 && <5 , containers diff --git a/code/cvss/src/Security/CVSS.hs b/code/cvss/src/Security/CVSS.hs index 1023917d..74acd8ad 100644 --- a/code/cvss/src/Security/CVSS.hs +++ b/code/cvss/src/Security/CVSS.hs @@ -34,7 +34,7 @@ import Data.String (IsString) import Data.Text (Text) import Data.Text qualified as Text import GHC.Float (powerFloat) -import Security.CVSS40Lookup (lookupScore, maxComposed, maxComposedEQ3, maxSeverity, maxSeverityeq3eq6) +import Security.V4_0.CVSS40Lookup (lookupScore, maxComposed, maxComposedEQ3, maxSeverity, maxSeverityeq3eq6) import qualified Data.Map as Map import Data.Either (rights) @@ -226,11 +226,14 @@ parseCVSS txt components withPrefix = (if withPrefix then drop 1 else id) $ Text.split (== '/') txt splitComponent :: Text -> Either CVSSError Metric - splitComponent componentTxt = case Text.unsnoc componentTxt of - Nothing -> Left EmptyComponent - Just (rest, c) -> case Text.unsnoc rest of - Just (name, ':') -> Right (Metric (MetricShortName name) (C c)) - _ -> Left (MissingValue componentTxt) + splitComponent componentTxt + | Text.null componentTxt = Left EmptyComponent + | otherwise = + let (name, valueWithColon) = Text.breakOn ":" componentTxt + value = Text.drop 1 valueWithColon + in if Text.null value + then Left (MissingValue componentTxt) + else Right (Metric (MetricShortName name) (S (Text.head value) (Text.unpack $ Text.tail value))) -- | Compute the base score. cvssScore :: CVSS -> (Rating, Float) @@ -614,61 +617,47 @@ parseMaxVectors txt = CVSS CVSS40 <$> parseMetrics calcSeverities :: [Metric] -> [Text] -> [Float] calcSeverities metrics maxVectors = - case find isValidMaxVector parsedMaxVectors of - Just maxVector -> - let - severityDistanceAV = gm metrics "AV" - gm (cvssMetrics maxVector) "AV" - severityDistancePR = gm metrics "PR" - gm (cvssMetrics maxVector) "PR" - severityDistanceUI = gm metrics "UI" - gm (cvssMetrics maxVector) "UI" - severityDistanceAC = gm metrics "AC" - gm (cvssMetrics maxVector) "AC" - severityDistanceAT = gm metrics "AT" - gm (cvssMetrics maxVector) "AT" - severityDistanceVC = gm metrics "VC" - gm (cvssMetrics maxVector) "VC" - severityDistanceVI = gm metrics "VI" - gm (cvssMetrics maxVector) "VI" - severityDistanceVA = gm metrics "VA" - gm (cvssMetrics maxVector) "VA" - severityDistanceSC = gm metrics "SC" - gm (cvssMetrics maxVector) "SC" - severityDistanceSI = gm metrics "SI" - gm (cvssMetrics maxVector) "SI" - severityDistanceSA = gm metrics "SA" - gm (cvssMetrics maxVector) "SA" - severityDistanceCR = gm metrics "CR" - gm (cvssMetrics maxVector) "CR" - severityDistanceIR = gm metrics "IR" - gm (cvssMetrics maxVector) "IR" - severityDistanceAR = gm metrics "AR" - gm (cvssMetrics maxVector) "AR" - in - [ severityDistanceAV + severityDistancePR + severityDistanceUI - , severityDistanceAC + severityDistanceAT - , severityDistanceVC + severityDistanceVI + severityDistanceVA + severityDistanceCR + severityDistanceIR + severityDistanceAR - , severityDistanceSC + severityDistanceSI + severityDistanceSA - , 0 - ] - Nothing -> [0, 0, 0, 0, 0] - where - gm :: [Metric] -> MetricShortName -> Float - gm = getCvssMetricV cvss40 - pMaxVectors = map parseMaxVectors maxVectors - parsedMaxVectors = rights pMaxVectors - isValidMaxVector maxVector = - let - severityDistanceAV = gm metrics "AV" - gm (cvssMetrics maxVector) "AV" - severityDistancePR = gm metrics "PR" - gm (cvssMetrics maxVector) "PR" - severityDistanceUI = gm metrics "UI" - gm (cvssMetrics maxVector) "UI" - severityDistanceAC = gm metrics "AC" - gm (cvssMetrics maxVector) "AC" - severityDistanceAT = gm metrics "AT" - gm (cvssMetrics maxVector) "AT" - severityDistanceVC = gm metrics "VC" - gm (cvssMetrics maxVector) "VC" - severityDistanceVI = gm metrics "VI" - gm (cvssMetrics maxVector) "VI" - severityDistanceVA = gm metrics "VA" - gm (cvssMetrics maxVector) "VA" - severityDistanceSC = gm metrics "SC" - gm (cvssMetrics maxVector) "SC" - severityDistanceSI = gm metrics "SI" - gm (cvssMetrics maxVector) "SI" - severityDistanceSA = gm metrics "SA" - gm (cvssMetrics maxVector) "SA" - severityDistanceCR = gm metrics "CR" - gm (cvssMetrics maxVector) "CR" - severityDistanceIR = gm metrics "IR" - gm (cvssMetrics maxVector) "IR" - severityDistanceAR = gm metrics "AR" - gm (cvssMetrics maxVector) "AR" - in - all (>= 0.0) [ severityDistanceAV, severityDistancePR, severityDistanceUI, severityDistanceAC, severityDistanceAT - , severityDistanceVC, severityDistanceVI, severityDistanceVA, severityDistanceSC, severityDistanceSI - , severityDistanceSA, severityDistanceCR, severityDistanceIR, severityDistanceAR ] + let calculatedSeverities = map calcMaxVectorSeverities parsedMaxVectors in + case find (all (>= 0.0)) calculatedSeverities of + Just [ severityDistanceAV, severityDistancePR, severityDistanceUI, severityDistanceAC, severityDistanceAT + , severityDistanceVC, severityDistanceVI, severityDistanceVA, severityDistanceSC, severityDistanceSI + , severityDistanceSA, severityDistanceCR, severityDistanceIR, severityDistanceAR ] -> + [ severityDistanceAV + severityDistancePR + severityDistanceUI + , severityDistanceAC + severityDistanceAT + , severityDistanceVC + severityDistanceVI + severityDistanceVA + severityDistanceCR + severityDistanceIR + severityDistanceAR + , severityDistanceSC + severityDistanceSI + severityDistanceSA + , 0 + ] + Nothing -> [0, 0, 0, 0, 0] + where + gm :: [Metric] -> MetricShortName -> Float + gm = getCvssMetricV cvss40 + pMaxVectors = map parseMaxVectors maxVectors + parsedMaxVectors = rights pMaxVectors + calcMaxVectorSeverities maxVector = + let + severityDistanceAV = gm metrics "AV" - gm (cvssMetrics maxVector) "AV" + severityDistancePR = gm metrics "PR" - gm (cvssMetrics maxVector) "PR" + severityDistanceUI = gm metrics "UI" - gm (cvssMetrics maxVector) "UI" + severityDistanceAC = gm metrics "AC" - gm (cvssMetrics maxVector) "AC" + severityDistanceAT = gm metrics "AT" - gm (cvssMetrics maxVector) "AT" + severityDistanceVC = gm metrics "VC" - gm (cvssMetrics maxVector) "VC" + severityDistanceVI = gm metrics "VI" - gm (cvssMetrics maxVector) "VI" + severityDistanceVA = gm metrics "VA" - gm (cvssMetrics maxVector) "VA" + severityDistanceSC = gm metrics "SC" - gm (cvssMetrics maxVector) "SC" + severityDistanceSI = gm metrics "SI" - gm (cvssMetrics maxVector) "SI" + severityDistanceSA = gm metrics "SA" - gm (cvssMetrics maxVector) "SA" + severityDistanceCR = gm metrics "CR" - gm (cvssMetrics maxVector) "CR" + severityDistanceIR = gm metrics "IR" - gm (cvssMetrics maxVector) "IR" + severityDistanceAR = gm metrics "AR" - gm (cvssMetrics maxVector) "AR" + in [ severityDistanceAV, severityDistancePR, severityDistanceUI, severityDistanceAC, severityDistanceAT + , severityDistanceVC, severityDistanceVI, severityDistanceVA, severityDistanceSC, severityDistanceSI + , severityDistanceSA, severityDistanceCR, severityDistanceIR, severityDistanceAR ] calcMeanDistance :: Maybe Float -> [Maybe Float] -> [Int] -> [Float] -> Int -> Float calcMeanDistance Nothing _ _ _ _ = 0 calcMeanDistance (Just value) nextLowerMacro macroVector currentSeverities eq6 = - if nExistingLower == 0.0 then 0.0 else (sum normalizedSeverities) / nExistingLower where + if nExistingLower == 0.0 then 0.0 else sum normalizedSeverities / nExistingLower where normalizedSeverities = zipWith calcNormalizedSeverity [0..] [0, 0, 0, 0, 0] nExistingLower :: Float nExistingLower = sum (zipWith (\i _ -> case nextLowerMacro !! i of diff --git a/code/cvss/src/Security/CVSS40Lookup.hs b/code/cvss/src/Security/V4_0/CVSS40Lookup.hs similarity index 98% rename from code/cvss/src/Security/CVSS40Lookup.hs rename to code/cvss/src/Security/V4_0/CVSS40Lookup.hs index 945899d5..dce47b25 100644 --- a/code/cvss/src/Security/CVSS40Lookup.hs +++ b/code/cvss/src/Security/V4_0/CVSS40Lookup.hs @@ -1,6 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} -module Security.CVSS40Lookup (lookupScore, maxComposed, maxComposedEQ3, maxSeverityeq3eq6, maxSeverity) where +module Security.V4_0.CVSS40Lookup (lookupScore, maxComposed, maxComposedEQ3, maxSeverityeq3eq6, maxSeverity) where import qualified Data.Map as Map import Data.Text (Text) diff --git a/code/cvss/test/Spec.hs b/code/cvss/test/Spec.hs index 19cb1512..621ebc98 100644 --- a/code/cvss/test/Spec.hs +++ b/code/cvss/test/Spec.hs @@ -23,8 +23,8 @@ runTest = map \(cvssString, score, rating) -> testCase (unpack cvssString) $ Left e -> assertFailure (show e) Right cvss -> do CVSS.cvssScore cvss @?= (rating, score) - -- CVSS.cvssVectorString cvss @?= cvssString TODO andrii - -- CVSS.cvssVectorStringOrdered cvss @?= cvssString TODO andrii + CVSS.cvssVectorString cvss @?= cvssString + CVSS.cvssVectorStringOrdered cvss @?= cvssString testCases30 :: [(Text, Float, CVSS.Rating)] testCases30 = @@ -55,10 +55,12 @@ testCases40 :: [(Text, Float, CVSS.Rating)] testCases40 = [ ("CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 7.3, CVSS.High) + , ("CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/U:Clear", 7.3, CVSS.High) + , ("CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/U:Red", 7.3, CVSS.High) , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N", 7.7, CVSS.High) , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:U", 5.2, CVSS.Medium) , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N", 8.3, CVSS.High) - , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N/CR:H/IR:L/AR:L/MAV:N/MAC:H/MVC:H/MVI:L/MVA:L", 8.1, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:L/VA:L/SC:N/SI:N/SA:N/MAV:N/MAC:H/MVC:H/MVI:L/MVA:L/CR:H/IR:L/AR:L", 8.1, CVSS.High) , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N", 4.6, CVSS.Medium) , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N", 5.1, CVSS.Medium) , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N", 6.9, CVSS.Medium) @@ -91,10 +93,11 @@ testCases40 = , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:L/SI:N/SA:H", 7.8, CVSS.High) , ("CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/S:P", 8.5, CVSS.High) , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/S:P/AU:Y/V:C/RE:L", 9.4, CVSS.Critical) - , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P/CR:L/IR:H/AR:L/MAV:L/MAC:H/MAT:N/MPR:N/MUI:N/MVC:N/MVI:H/MVA:L/MSC:N/MSI:S/MSA:L", 7.0, CVSS.High) - , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/MAV:A/MAC:H/MAT:N/MPR:L/MUI:N/MVC:L/MVI:H/MVA:H/MSC:L/MSI:S/MSA:S/CR:L/IR:H/AR:H/E:P", 7.4, CVSS.High) - , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P/CR:L/IR:H/AR:H/MAV:A/MAC:H/MAT:N/MPR:L/MUI:N/MVC:L/MVI:H/MVA:H/MSC:L/MSI:S/MSA:S", 7.4, CVSS.High) - , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/MAV:N/MAC:H/MAT:N/MPR:L/MUI:N/MVC:H/MVI:H/MVA:H/MSC:H/MSI:S/MSA:H/CR:M/IR:H/AR:M/E:P", 8.7, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P/MAV:L/MAC:H/MAT:N/MPR:N/MUI:N/MVC:N/MVI:H/MVA:L/MSC:N/MSI:S/MSA:L/CR:L/IR:H/AR:L", 7.0, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P/MAV:A/MAC:H/MAT:N/MPR:L/MUI:N/MVC:L/MVI:H/MVA:H/MSC:L/MSI:S/MSA:S/CR:L/IR:H/AR:H", 7.4, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P/MAV:A/MAC:H/MAT:N/MPR:L/MUI:N/MVC:L/MVI:H/MVA:H/MSC:L/MSI:S/MSA:S/CR:L/IR:H/AR:H", 7.4, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P/MAV:A/MAC:H/MAT:N/MPR:L/MUI:N/MVC:L/MVI:H/MVA:H/MSC:L/MSI:S/MSA:S/CR:L/IR:H/AR:H", 7.4, CVSS.High) + , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P/MAV:N/MAC:H/MAT:N/MPR:L/MUI:N/MVC:H/MVI:H/MVA:H/MSC:H/MSI:S/MSA:H/CR:M/IR:H/AR:M", 8.7, CVSS.High) , ("CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/S:P", 8.6, CVSS.High) , ("CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/MSI:S/S:P", 9.7, CVSS.Critical) , ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/V:C", 8.7, CVSS.High)