├── lib ├── __init__.py ├── metrics.py ├── formulas.py └── pycvss3.py ├── CREDITS ├── cvss_3.calc.py ├── README.md ├── LICENSE.md └── api_call.py /lib/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 ToolsWatch.org 2 | # This file is part of vFeed Aggregated Vulnerability Database Community -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | **CREDITS** 2 | 3 | This file is used to state the core developers team 4 | 5 | *ToolsWatch* 6 | 7 | NJ OUCHN - @toolswatch - (Project Lead and Developer) 8 | -------------------------------------------------------------------------------- /cvss_3.calc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (C) 2015 ToolsWatch.org 3 | # This file is part of vFeed Aggregated Vulnerability Database Community 4 | __version__ = 0.3 5 | __author__ = "NJ OUCHN (@toolswatch)" 6 | 7 | import argparse 8 | from lib.pycvss3 import CVSS3 9 | 10 | if __name__ == "__main__": 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument("-v", "--version", action="version", 13 | version="pycvss3 - The CVSS v3 Python Calculator version {0} by {1} ".format(__version__, __author__)) 14 | parser.add_argument("--vector", metavar="Vector mode", type=str, 15 | help="Paste the CVSS v3 vector string (without CVSS:3.0/) ") 16 | args = parser.parse_args() 17 | 18 | if args.vector: 19 | cvss3 = CVSS3(args.vector) 20 | (cvss_base_value, cvss_base_risk_level) = cvss3.cvss_base_score() 21 | (cvss_temporal_value, cvss_temporal_risk_level) = cvss3.cvss_temporal_score() 22 | (cvss_environmental_value, cvss_environmental_risk_level) = cvss3.cvss_environmental_score() 23 | 24 | print "CVSS v3 vector:", args.vector 25 | print "\tCVSS 3 Base Score: %s | Rating : %s" % (cvss_base_value, cvss_base_risk_level) 26 | print "\tCVSS 3 Temporal Score: %s | Rating : %s" % (cvss_temporal_value, cvss_temporal_risk_level) 27 | print "\tCVSS 3 Environmental Score: %s | Rating : %s" % ( 28 | cvss_environmental_value, cvss_environmental_risk_level) 29 | -------------------------------------------------------------------------------- /lib/metrics.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (C) 2015 ToolsWatch.org 3 | # This file is part of vFeed Aggregated Vulnerability Database Community 4 | 5 | 6 | class Value: 7 | def __init__(self, **entries): 8 | self.__dict__.update(entries) 9 | 10 | 11 | class Metrics: 12 | """ 13 | This class returns the metric values as defined by the CVSS v3 specification doc. https://www.first.org/cvss/specification-document 14 | I added not_defined key to base metrics to deal with the Modified Base Metrics as they have the same values 15 | as the corresponding Base Metrics 16 | """ 17 | 18 | # Base Metrics 19 | attack_vector = Value(not_defined=float(0.85), network=float(0.85), adjacent_network=float(0.62), local=float(0.55), 20 | physical=float(0.20)) 21 | attack_complexity = Value(not_defined=float(0.77), low=float(0.77), high=float(0.44)) 22 | privileges_required = Value(not_defined=float(0.85), none=float(0.85), low=float(0.62), high=float(0.27)) 23 | privileges_required_changed = Value(not_defined=float(0.85), none=float(0.85), low=float(0.68), high=float(0.50)) 24 | user_interaction = Value(not_defined=float(0.85), none=float(0.85), required=float(0.62)) 25 | cia_impact = Value(not_defined=float(0.56), high=float(0.56), low=float(0.22), none=float(0)) 26 | 27 | # Temporal Metrics 28 | exploit_code_maturity = Value(not_defined=float(1.0), high=float(1), functional=float(0.97), 29 | proof_of_concept=float(0.94), unproven=float(0.91)) 30 | remediation_level = Value(not_defined=float(1.0), unavailable=float(1), workaround=float(0.97), 31 | temporary_fix=float(0.96), official_fix=float(0.95)) 32 | report_confidence = Value(not_defined=float(1.0), confirmed=float(1), reasonable=float(0.96), unknown=float(0.92)) 33 | 34 | # Environmental Metrics 35 | cia_requirement = Value(not_defined=float(1.0), high=float(1.5), medium=float(1.0), low=float(0.50)) 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pycvss3 - Python API for the CVSS v3 2 | 3 | First.org made available the version 3 of the Common Vulnerability Scoring System (CVSS). The new system is the latest update of the universal open and standardized method for rating IT vulnerabilities and determining the urgency of response. 4 | The updated version includes enhancements such as: the promotion of consistency in scoring, the replacement of Scoring Tips in order to more clearly guide end users of CVSS, and consideration of the system in order to make it more applicable to modern concerns. More information on the standard is available at https://www.first.org/cvss. 5 | 6 | pycvss3 is Python library calculator for the newest CVSS v3 and can be invoked from scripts as API or directly from command line. The API and CLI can both display the score alongside the Qualitative Rating Scale 7 | 8 | 9 | 10 | 11 | Basic usage 12 | ============== 13 |
14 | ./cvss_3.calc.py --vector AV:P/AC:H/PR:H/UI:R/S:C/C:N/I:N/A:N/E:P/RL:T/RC:R/CR:L/IR:L/AR:L/MAV:P/MAC:H/MPR:H/MUI:R/MS:U/MC:N/MI:N/MA:N
15 | CVSS v3 vector: AV:P/AC:H/PR:H/UI:R/S:C/C:N/I:N/A:N/E:P/RL:T/RC:R/CR:L/IR:L/AR:L/MAV:P/MAC:H/MPR:H/MUI:R/MS:U/MC:N/MI:N/MA:N
16 | CVSS 3 Base Score: 0.0 --> Risk Level: None
17 | CVSS 3 Temporal Score: 0.0 --> Risk Level: None
18 | CVSS 3 Environmental Score: 0.0 --> Risk Level: None
19 |
20 | ./cvss_3.calc.py --vector AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:H/E:H/RL:W/RC:U/CR:H/IR:H/AR:M/MAV:L/MAC:L/MPR:H/MUI:N/MS:C/MC:N/MI:H/MA:L
21 | CVSS v3 vector: AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:H/E:H/RL:W/RC:U/CR:H/IR:H/AR:M/MAV:L/MAC:L/MPR:H/MUI:N/MS:C/MC:N/MI:H/MA:L
22 | CVSS 3 Base Score: 5.8 | Rating : Medium
23 | CVSS 3 Temporal Score: 5.2 | Rating : Medium
24 | CVSS 3 Environmental Score: 7.4 | Rating : High
25 |
26 |
27 | Calling the API
28 | ==============
29 |
30 | Edit the `api_call.py` to see how to leverage the class from your scripts.
31 |
32 | To do
33 | ==============
34 |
35 | * Clean and optimize the pycvss3 code
36 |
37 | v0.3
38 | ---------
39 | * Added the support to the Qualitative Rating scale as defined in the CVSS v3 User Guide >> https://www.first.org/cvss/user-guide
40 | * Renamed and refactored the Vector Class to CVSS3
41 | * Update the pycvss3.py to reflect the change.
42 |
43 | v0.2
44 | ---------
45 | * Added support to Environmental score.
46 | * Fixed few calculation bugs in pycvss.py class
47 | * Fixed the non_defined valued in metrics.py class
48 |
49 | v0.1
50 | ---------
51 | * Initial release with the ability to calculatec the Base and Temporal scores in compliance with the CVSS v3.0 specifications (https://www.first.org/cvss/specification-document)
52 | The environmental score will be added later despite the fact the formula is in the code and working great.
53 | * Added api_call.py to demonstrate how to invoke the class.
54 | * Added the cvss_3.calc.py command line that accepts the CVSS v3.0 vector as input.
55 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # pycvss3 Public Source License
2 |
3 | The pycvss3 software (henceforth referred to simply as "pycvss3") is dual-licensed - Copyright 2004-2015 ToolsWatch Org.
4 |
5 | Cases that include commercialization of pycvss3 require a commercial, non-free license. Otherwise, pycvss3 can be used without charge under the terms set out below.
6 |
7 | ## 1. Definitions
8 |
9 | 1.1 "License" means this document.
10 |
11 | 1.2 "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns pycvss3.
12 |
13 | 1.3 "ToolsWatch Org." means pycvss3’s core developers, an updated list of whom can be found within the CREDITS file.
14 |
15 |
16 | ## 2. Commercialization
17 |
18 | A commercial use is one intended for commercial advantage or monetary compensation.
19 |
20 | Example cases of commercialization are:
21 |
22 | * Using pycvss3 to provide commercial managed/Software-as-a-Service services.
23 | * Distributing pycvss3 as a commercial product or as part of one.
24 | * Using pycvss3 as a value added service/product.
25 |
26 | Example cases which do not require a commercial license, and thus fall under the terms set out below, include (but are not limited to):
27 |
28 | Penetration testers (or penetration testing organizations) using pycvss3 as part of their assessment toolkit.
29 |
30 | * Penetration Testing Linux Distributions including but not limited to Kali Linux, SamuraiWTF, BackBox Linux.
31 | * Using pycvss3 to calculate your own systems scoring.
32 | * Any non-commercial use of pycvss3.
33 |
34 | If you need to purchase a commercial license or are unsure whether you need to purchase a commercial license contact us - hacker@toolswatch.org
35 |
36 | We may grant commercial licenses at no monetary cost at our own discretion if the commercial usage is deemed by the ToolsWatch Org. to significantly benefit pycvss3.
37 |
38 | Free-use Terms and Conditions;
39 |
40 | ## 3.Redistribution
41 |
42 | Redistribution is permitted under the following conditions:
43 |
44 | * Unmodified License is provided with pycvss3.
45 | * Unmodified Copyright notices are provided with pycvss3.
46 | * Does not conflict with the commercialization clause.
47 |
48 | ## 4. Copying
49 |
50 | Copying is permitted so long as it does not conflict with the Redistribution clause.
51 |
52 | ## 5. Modification
53 |
54 | Modification is permitted so long as it does not conflict with the Redistribution clause.
55 |
56 | ## 6. Contributions
57 |
58 | Any Contributions assume the Contributor grants the ToolsWatch Org. the unlimited, non-exclusive right to reuse, modify and relicense the Contributor's content.
59 |
60 | ## 7. Support
61 |
62 | pycvss3 is provided under an “as is” basis and without any support, updates or maintenance. Support, updates and maintenance may be given according to the sole discretion of the ToolsWatch Org.
63 |
64 | ## 8. Disclaimer of Warranty
65 |
66 | pycvss3 is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the pycvss3 is free of defects, merchantable, fit for a particular purpose or non-infringing.
67 |
68 | ## 9. Limitation of Liability
69 |
70 | To the extent permitted under Law, pycvss3 is provided under an AS-IS basis. The ToolsWatch Org. shall never, and without any limit, be liable for any damage, cost, expense or any other payment incurred as a result of pycvss3's actions, failure, bugs and/or any other interaction between pycvss3 and end-equipment, computers, other software or any 3rd party, end-equipment, computer or services.
71 |
72 | ## 10. Disclaimer
73 |
74 | The ToolsWatch Org. accept no liability and are not responsible for any misuse or damage caused by pycvss3.
--------------------------------------------------------------------------------
/api_call.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright (C) 2015 ToolsWatch.org
3 | # This file is part of vFeed Aggregated Vulnerability Database Community
4 |
5 | from lib.pycvss3 import CVSS3
6 |
7 | print "Example 1"
8 | cvss3_vector = "AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N/E:H/RL:O/RC:C/CR:H/IR:H/AR:H/MAV:N/MAC:L/MPR:L/MUI:N/MS:C/MC:H/MI:H/MA:H"
9 | cvss3 = CVSS3(cvss3_vector)
10 | cvss_base_score_risk = cvss3.cvss_base_score()
11 | cvss_temporal_score_risk = cvss3.cvss_temporal_score()
12 | print "CVSS v3 vector:", cvss3_vector
13 | print "\tCVSS v3 Base Score and Risk Level", cvss_base_score_risk
14 | print "\tCVSS v3 Temporal Score:", cvss_temporal_score_risk
15 |
16 | print ""
17 | print "Example 2"
18 | cvss3_vector = "AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H/E:U/RL:X/RC:X"
19 | cvss3 = CVSS3(cvss3_vector)
20 | cvss_base_score_risk = cvss3.cvss_base_score()
21 | cvss_temporal_score_risk = cvss3.cvss_temporal_score()
22 | print "CVSS v3 vector:", cvss3_vector
23 | print "\tCVSS v3 Base Score and Risk Level", cvss_base_score_risk
24 | print "\tCVSS v3 Temporal Score:", cvss_temporal_score_risk
25 |
26 | print ""
27 | print "Example 3"
28 | cvss3_vector = "AV:P/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:N/E:X/RL:X/RC:X"
29 | cvss3 = CVSS3(cvss3_vector)
30 | cvss_base_score_risk = cvss3.cvss_base_score()
31 | cvss_temporal_score_risk = cvss3.cvss_temporal_score()
32 | print "CVSS v3 vector:", cvss3_vector
33 | print "\tCVSS v3 Base Score and Risk Level", cvss_base_score_risk
34 | print "\tCVSS v3 Temporal Score:", cvss_temporal_score_risk
35 |
36 | print ""
37 | print "Example 4"
38 | cvss3_vector = "AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H/E:H/RL:U/RC:C/CR:H/IR:H/AR:H/MAV:N/MAC:L/MPR:L/MUI:N/MS:C/MC:H/MI:H/MA:H"
39 | cvss3 = CVSS3(cvss3_vector)
40 | cvss_base_score_risk = cvss3.cvss_base_score()
41 | cvss_temporal_score_risk = cvss3.cvss_temporal_score()
42 | cvss_environmental_score_risk = cvss3.cvss_environmental_score()
43 | print "CVSS v3 vector:", cvss3_vector
44 | print "\tCVSS v3 Base Score:", cvss_base_score_risk
45 | print "\tCVSS v3 Temporal Score:", cvss_temporal_score_risk
46 | print "\tCVSS 3 Environmental Score:", cvss_environmental_score_risk
47 |
48 | print ""
49 | print "Example 5"
50 | cvss3_vector = "AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H/E:H/RL:U/RC:C/CR:H/IR:H/AR:H/MAV:N/MAC:L/MPR:H/MUI:N/MS:U/MC:L/MI:H/MA:L"
51 | cvss3 = CVSS3(cvss3_vector)
52 | cvss_base_score_risk = cvss3.cvss_base_score()
53 | cvss_temporal_score_risk = cvss3.cvss_temporal_score()
54 | cvss_environmental_score_risk = cvss3.cvss_environmental_score()
55 | print "CVSS v3 vector:", cvss3_vector
56 | print "\tCVSS v3 Base Score:", cvss_base_score_risk
57 | print "\tCVSS v3 Temporal Score:", cvss_temporal_score_risk
58 | print "\tCVSS 3 Environmental Score:", cvss_environmental_score_risk
59 |
60 | print ""
61 | print "Example 6"
62 | cvss3_vector = "AV:P/AC:H/PR:H/UI:R/S:C/C:N/I:N/A:N/E:P/RL:T/RC:R/CR:L/IR:L/AR:L/MAV:N/MAC:L/MPR:N/MUI:N/MS:C/MC:H/MI:H/MA:H"
63 | cvss3 = CVSS3(cvss3_vector)
64 | cvss_base_score_risk = cvss3.cvss_base_score()
65 | cvss_temporal_score_risk = cvss3.cvss_temporal_score()
66 | cvss_environmental_score_risk = cvss3.cvss_environmental_score()
67 | print "CVSS v3 vector:", cvss3_vector
68 | print "\tCVSS v3 Base Score:", cvss_base_score_risk
69 | print "\tCVSS v3 Temporal Score:", cvss_temporal_score_risk
70 | print "\tCVSS 3 Environmental Score:", cvss_environmental_score_risk
71 |
72 | print ""
73 | print "Example 7"
74 | cvss3_vector = "AV:P/AC:H/PR:H/UI:R/S:C/C:N/I:N/A:N/E:P/RL:T/RC:R/CR:L/IR:L/AR:L/MAV:P/MAC:H/MPR:H/MUI:R/MS:U/MC:N/MI:N/MA:N"
75 | cvss3 = CVSS3(cvss3_vector)
76 | cvss_base_score_risk = cvss3.cvss_base_score()
77 | cvss_temporal_score_risk = cvss3.cvss_temporal_score()
78 | cvss_environmental_score_risk = cvss3.cvss_environmental_score()
79 | print "CVSS v3 vector:", cvss3_vector
80 | print "\tCVSS v3 Base Score:", cvss_base_score_risk
81 | print "\tCVSS v3 Temporal Score:", cvss_temporal_score_risk
82 | print "\tCVSS 3 Environmental Score:", cvss_environmental_score_risk
83 |
84 | print ""
85 | print "Example 8 - Printing only scores"
86 | cvss3_vector = "AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:H/E:H/RL:W/RC:U/CR:H/IR:H/AR:M/MAV:L/MAC:L/MPR:H/MUI:N/MS:C/MC:N/MI:H/MA:L"
87 | cvss3 = CVSS3(cvss3_vector)
88 | (cvss_base_score,cvss_base_risk) = cvss3.cvss_base_score()
89 | (cvss_temporal_score,cvss_temporal_risk) = cvss3.cvss_temporal_score()
90 | (cvss_environmental_score,cvss_environmental_risk)= cvss3.cvss_environmental_score()
91 | print "CVSS v3 vector:", cvss3_vector
92 | print "\tCVSS v3 Base Score:", cvss_base_score
93 | print "\tCVSS v3 Temporal Score:", cvss_temporal_score
94 | print "\tCVSS 3 Environmental Score:", cvss_environmental_score
95 |
96 | print ""
97 | print "Example 9 - Printing only ratings"
98 | cvss3_vector = "AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:H/E:H/RL:W/RC:U/CR:H/IR:H/AR:M/MAV:L/MAC:L/MPR:H/MUI:N/MS:C/MC:N/MI:H/MA:L"
99 | cvss3 = CVSS3(cvss3_vector)
100 | (cvss_base_score,cvss_base_risk) = cvss3.cvss_base_score()
101 | (cvss_temporal_score,cvss_temporal_risk) = cvss3.cvss_temporal_score()
102 | (cvss_environmental_score,cvss_environmental_risk)= cvss3.cvss_environmental_score()
103 | print "CVSS v3 vector:", cvss3_vector
104 | print "\tCVSS v3 Base rating:", cvss_base_risk
105 | print "\tCVSS v3 Temporal rating:", cvss_temporal_risk
106 | print "\tCVSS 3 Environmental rating:", cvss_environmental_risk
107 |
--------------------------------------------------------------------------------
/lib/formulas.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright (C) 2015 ToolsWatch.org
3 | # This file is part of vFeed Aggregated Vulnerability Database Community
4 |
5 | import math
6 |
7 |
8 | def exploitability_sub_score(attack_vector_value, attack_complexity_value, privileges_required_value,
9 | user_interaction_value):
10 | """
11 | :param attack_vector_value:
12 | :param attack_complexity_value:
13 | :param privileges_required_value:
14 | :param user_interaction_value:
15 | :return: the exploitability sub score required for the CVSS Base
16 | """
17 | exploitability_sub_score_value = 8.22 * attack_vector_value * attack_complexity_value * privileges_required_value * \
18 | user_interaction_value
19 | return exploitability_sub_score_value
20 |
21 |
22 | def exploitability_sub_score_modified(attack_vector_value_modified, attack_complexity_value_modified,
23 | privileges_required_value_modified,
24 | user_interaction_value_modified):
25 | """
26 | :param attack_vector_value_modified:
27 | :param attack_complexity_value_modified:
28 | :param privileges_required_value_modified:
29 | :param user_interaction_value_modified:
30 | :return: The modified exploitability sub score as required by the Environmental score
31 | """
32 | exploitability_sub_score_value_modified = 8.22 * attack_vector_value_modified * attack_complexity_value_modified * privileges_required_value_modified * \
33 | user_interaction_value_modified
34 | return exploitability_sub_score_value_modified
35 |
36 | def impact_sub_score(availability_value, confidentiality_value, integrity_value):
37 | """
38 | :param availability_value:
39 | :param confidentiality_value:
40 | :param integrity_value:
41 | :return: Impact sub score value as required by the Base score
42 | """
43 | impact_sub_score_value = 1 - ((1 - confidentiality_value) * (1 - integrity_value) * (1 - availability_value))
44 | return impact_sub_score_value
45 |
46 |
47 | def impact_sub_score_modified(availability_value_modified, confidentiality_value_modified, integrity_value_modified,
48 | confidentiality_requirement_value, integrity_requirement_value,
49 | availability_requirement_value):
50 | """
51 | :param availability_value_modified:
52 | :param confidentiality_value_modified:
53 | :param integrity_value_modified:
54 | :param confidentiality_requirement_value:
55 | :param integrity_requirement_value:
56 | :param availability_requirement_value:
57 | :return: the modified Impact sub score as required by the Environmental score
58 | """
59 | impact_sub_score_value_modified = min(0.915, 1 - (
60 | 1 - confidentiality_value_modified * confidentiality_requirement_value) * (
61 | 1 - integrity_value_modified * integrity_requirement_value) * (
62 | 1 - availability_value_modified * availability_requirement_value))
63 | return impact_sub_score_value_modified
64 |
65 |
66 | def cvss_base_formula(impact_sub_score_value, scope_value, exploitability_sub_score_value):
67 | """
68 | :param impact_sub_score_value:
69 | :param scope_value:
70 | :param exploitability_sub_score_value:
71 | :return: the cvss base value
72 | """
73 | if scope_value == "unchanged":
74 | impact_value = 6.42 * impact_sub_score_value
75 | cvss_base_value = min(10, impact_value + exploitability_sub_score_value)
76 |
77 | elif scope_value == "changed":
78 | impact_value = 7.52 * (impact_sub_score_value - 0.029) - 3.25 * math.pow(
79 | impact_sub_score_value - 0.02, 15)
80 | cvss_base_value = min(10, 1.08 * (impact_value + exploitability_sub_score_value))
81 |
82 | if impact_sub_score_value <= 0:
83 | cvss_base_value = float(0.0)
84 | else:
85 | cvss_base_value = math.ceil(cvss_base_value * 10) / 10
86 | return cvss_base_value
87 |
88 |
89 | def cvss_temporal_formula(cvss_base_value, exploit_code_maturity_value, remediation_level_value,
90 | report_confidence_value):
91 | """
92 | :param cvss_base_value:
93 | :param exploit_code_maturity_value:
94 | :param remediation_level_value:
95 | :param report_confidence_value:
96 | :return: the temporal score value
97 | """
98 | cvss_temporal_value = cvss_base_value * exploit_code_maturity_value * remediation_level_value * \
99 | report_confidence_value
100 | cvss_temporal_value = math.ceil(cvss_temporal_value * 10) / 10
101 | return cvss_temporal_value
102 |
103 |
104 | def cvss_environmental_formula(impact_sub_score_value_modified, exploitability_sub_score_value_modified,
105 | exploit_code_maturity_value, remediation_level_value, report_confidence_value,
106 | scope_value_modified):
107 | """
108 | :param impact_sub_score_value_modified:
109 | :param exploitability_sub_score_value_modified:
110 | :param exploit_code_maturity_value:
111 | :param remediation_level_value:
112 | :param report_confidence_value:
113 | :param scope_value_modified:
114 | :return: the environmental score value
115 | """
116 | if scope_value_modified == "unchanged":
117 | impact_value_modified = 6.42 * impact_sub_score_value_modified
118 | temp_score = min(10, impact_value_modified + exploitability_sub_score_value_modified)
119 | temp_score2 = math.ceil(temp_score * 10) / 10
120 | temp_score3 = temp_score2 * exploit_code_maturity_value * remediation_level_value * report_confidence_value
121 |
122 | else:
123 | scope_value_modified == "changed"
124 | impact_value_modified = 7.52 * (impact_sub_score_value_modified - 0.029) - 3.25 * math.pow(
125 | impact_sub_score_value_modified - 0.02, 15)
126 | temp_score = min(10, 1.08 * (impact_value_modified + exploitability_sub_score_value_modified))
127 | temp_score2 = math.ceil(temp_score * 10) / 10
128 | temp_score3 = temp_score2 * exploit_code_maturity_value * remediation_level_value * report_confidence_value
129 |
130 | if impact_sub_score_value_modified <= 0:
131 | cvss_environmental_value = float(0.0)
132 | return cvss_environmental_value
133 | else:
134 | cvss_environmental_value = math.ceil(temp_score3 * 10) / 10
135 | return cvss_environmental_value
136 |
--------------------------------------------------------------------------------
/lib/pycvss3.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright (C) 2015 ToolsWatch.org
3 | # This file is part of vFeed Aggregated Vulnerability Database Community
4 |
5 | from metrics import Metrics
6 | from formulas import *
7 |
8 |
9 | class CVSS3(object):
10 | def __init__(self, vector):
11 | self.vectors = vector.split('/')
12 |
13 | # case of temporal vector not set
14 | self.ecm_metric = "unset"
15 | self.rl_metric = "unset"
16 | self.rc_metric = "unset"
17 |
18 | # case of environmental metrics not set
19 | self.cr_metric = "unset"
20 | self.ir_metric = "unset"
21 | self.ar_metric = "unset"
22 |
23 | # case of modified base metrics not set
24 | self.mav_metric = "unset"
25 | self.mac_metric = "unset"
26 | self.mpr_metric = "unset"
27 | self.mui_metric = "unset"
28 | self.mc_metric = "unset"
29 | self.mi_metric = "unset"
30 | self.ma_metric = "unset"
31 |
32 | def get_vectors(self):
33 | """ Extract metrics from CVSS v3 vector format and set value of metrics to the appropriate value
34 | :return: Metrics values
35 | """
36 | for self.vector in self.vectors:
37 | self.splitted = self.vector[0:].split(':')
38 | self.metric_vector = self.splitted[0]
39 | self.metric_value = self.splitted[1]
40 |
41 | if self.metric_vector == "AV":
42 | if self.metric_value == "N" or self.metric_value == "network":
43 | self.attack_vector_value = Metrics.attack_vector.network
44 | if self.metric_value == "A" or self.metric_value == "adjacent_network":
45 | self.attack_vector_value = Metrics.attack_vector.adjacent_network
46 | if self.metric_value == "L" or self.metric_value == "local":
47 | self.attack_vector_value = Metrics.attack_vector.local
48 | if self.metric_value == "P" or self.metric_value == "physical":
49 | self.attack_vector_value = Metrics.attack_vector.physical
50 |
51 | if self.metric_vector == "AC":
52 | if self.metric_value == "L" or self.metric_value == "low":
53 | self.attack_complexity_value = Metrics.attack_complexity.low
54 | if self.metric_value == "H" or self.metric_value == "high":
55 | self.attack_complexity_value = Metrics.attack_complexity.high
56 |
57 | if self.metric_vector == "UI":
58 | if self.metric_value == "N" or self.metric_value == "none":
59 | self.user_interaction_value = Metrics.user_interaction.none
60 | if self.metric_value == "R" or self.metric_value == "required":
61 | self.user_interaction_value = Metrics.user_interaction.required
62 |
63 | # Assigning the appropriate value to PR depending on the Scope. See the formula.
64 | if self.metric_vector == "S":
65 | self.scope_value = self.metric_value
66 | # getting the value of PR vector from the original splitted vectors
67 | self.splitted_2 = self.vectors[3:4][0].split(':')
68 | self.metric_vector = self.splitted_2[0]
69 | self.metric_value = self.splitted_2[1]
70 |
71 | if self.scope_value == "C" or self.scope_value == "changed":
72 | self.scope_value = "changed"
73 | if self.metric_vector == "PR":
74 | if self.metric_value == "N" or self.metric_value == "none":
75 | self.privileges_required_value = Metrics.privileges_required_changed.none
76 | if self.metric_value == "L" or self.metric_value == "low":
77 | self.privileges_required_value = Metrics.privileges_required_changed.low
78 | if self.metric_value == "H" or self.metric_value == "high":
79 | self.privileges_required_value = Metrics.privileges_required_changed.high
80 | else:
81 | self.scope_value = "unchanged"
82 | if self.metric_value == "N" or self.metric_value == "none":
83 | self.privileges_required_value = Metrics.privileges_required.none
84 | elif self.metric_value == "L" or self.metric_value == "low":
85 | self.privileges_required_value = Metrics.privileges_required.low
86 | elif self.metric_value == "H" or self.metric_value == "high":
87 | self.privileges_required_value = Metrics.privileges_required.high
88 | else:
89 | raise Exception, "(PR) Privileges Required metric is not correct"
90 |
91 | if self.metric_vector == "C":
92 | if self.metric_value == "L" or self.metric_value == "low":
93 | self.confidentiality_value = Metrics.cia_impact.low
94 | elif self.metric_value == "H" or self.metric_value == "high":
95 | self.confidentiality_value = Metrics.cia_impact.high
96 | elif self.metric_value == "N" or self.metric_value == "none":
97 | self.confidentiality_value = Metrics.cia_impact.none
98 | else:
99 | raise Exception, "(C) Confidentiality metric is not correct"
100 |
101 | if self.metric_vector == "I":
102 | if self.metric_value == "L" or self.metric_value == "low":
103 | self.integrity_value = Metrics.cia_impact.low
104 | elif self.metric_value == "H" or self.metric_value == "high":
105 | self.integrity_value = Metrics.cia_impact.high
106 | elif self.metric_value == "N" or self.metric_value == "none":
107 | self.integrity_value = Metrics.cia_impact.none
108 | else:
109 | raise Exception, "(I) Integrity metric is not correct"
110 |
111 | if self.metric_vector == "A":
112 | if self.metric_value == "L" or self.metric_value == "low":
113 | self.availability_value = Metrics.cia_impact.low
114 | elif self.metric_value == "H" or self.metric_value == "high":
115 | self.availability_value = Metrics.cia_impact.high
116 | elif self.metric_value == "N" or self.metric_value == "none":
117 | self.availability_value = Metrics.cia_impact.none
118 | else:
119 | raise Exception, "(A) Availability metric is not correct"
120 |
121 | if self.metric_vector == "E":
122 | self.ecm_metric = "set"
123 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
124 | self.exploit_code_maturity_value = Metrics.exploit_code_maturity.not_defined
125 | elif self.metric_value == "H" or self.metric_value == "high":
126 | self.exploit_code_maturity_value = Metrics.exploit_code_maturity.high
127 | elif self.metric_value == "F" or self.metric_value == "functional":
128 | self.exploit_code_maturity_value = Metrics.exploit_code_maturity.functional
129 | elif self.metric_value == "P" or self.metric_value == "proof_of_concept" or self.metric_value == "proof of concept":
130 | self.exploit_code_maturity_value = Metrics.exploit_code_maturity.proof_of_concept
131 | elif self.metric_value == "U" or self.metric_value == "unproven":
132 | self.exploit_code_maturity_value = Metrics.exploit_code_maturity.unproven
133 | else:
134 | if self.ecm_metric != "set":
135 | self.exploit_code_maturity_value = Metrics.exploit_code_maturity.not_defined
136 |
137 | if self.metric_vector == "RL":
138 | self.rl_metric = "set"
139 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
140 | self.remediation_level_value = Metrics.remediation_level.not_defined
141 | elif self.metric_value == "U" or self.metric_value == "unavailable":
142 | self.remediation_level_value = Metrics.remediation_level.unavailable
143 | elif self.metric_value == "W" or self.metric_value == "workaround":
144 | self.remediation_level_value = Metrics.remediation_level.workaround
145 | elif self.metric_value == "T" or self.metric_value == "temporary_fix" or self.metric_value == "temporary fix":
146 | self.remediation_level_value = Metrics.remediation_level.temporary_fix
147 | elif self.metric_value == "O" or self.metric_value == "official_fix" or self.metric_value == "official fix":
148 | self.remediation_level_value = Metrics.remediation_level.official_fix
149 | else:
150 | if self.rl_metric != "set":
151 | self.remediation_level_value = Metrics.remediation_level.not_defined
152 |
153 | if self.metric_vector == "RC":
154 | self.rc_metric = "set"
155 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
156 | self.report_confidence_value = Metrics.remediation_level.not_defined
157 | elif self.metric_value == "C" or self.metric_value == "confirmed":
158 | self.report_confidence_value = Metrics.report_confidence.confirmed
159 | elif self.metric_value == "R" or self.metric_value == "reasonable":
160 | self.report_confidence_value = Metrics.report_confidence.reasonable
161 | elif self.metric_value == "U" or self.metric_value == "unknown":
162 | self.report_confidence_value = Metrics.report_confidence.unknown
163 | else:
164 | if self.rc_metric != "set":
165 | # Assigning the default value in case
166 | self.report_confidence_value = Metrics.report_confidence.not_defined
167 |
168 | if self.metric_vector == "CR":
169 | self.cr_metric = "set"
170 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
171 | self.confidentiality_requirement_value = Metrics.cia_requirement.not_defined
172 | elif self.metric_value == "H" or self.metric_value == "high":
173 | self.confidentiality_requirement_value = Metrics.cia_requirement.high
174 | elif self.metric_value == "M" or self.metric_value == "medium":
175 | self.confidentiality_requirement_value = Metrics.cia_requirement.medium
176 | elif self.metric_value == "L" or self.metric_value == "low":
177 | self.confidentiality_requirement_value = Metrics.cia_requirement.low
178 | else:
179 | if self.cr_metric != "set":
180 | self.confidentiality_requirement_value = Metrics.cia_requirement.not_defined
181 | if self.metric_vector == "IR":
182 | self.ir_metric = "set"
183 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
184 | self.integrity_requirement_value = Metrics.cia_requirement.not_defined
185 | elif self.metric_value == "H" or self.metric_value == "high":
186 | self.integrity_requirement_value = Metrics.cia_requirement.high
187 | elif self.metric_value == "M" or self.metric_value == "medium":
188 | self.integrity_requirement_value = Metrics.cia_requirement.medium
189 | elif self.metric_value == "L" or self.metric_value == "low":
190 | self.integrity_requirement_value = Metrics.cia_requirement.low
191 | else:
192 | if self.ir_metric != "set":
193 | self.integrity_requirement_value = Metrics.cia_requirement.not_defined
194 |
195 | if self.metric_vector == "AR":
196 | self.ar_metric = "set"
197 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
198 | self.availability_requirement_value = Metrics.cia_requirement.not_defined
199 | elif self.metric_value == "H" or self.metric_value == "high":
200 | self.availability_requirement_value = Metrics.cia_requirement.high
201 | elif self.metric_value == "M" or self.metric_value == "medium":
202 | self.availability_requirement_value = Metrics.cia_requirement.medium
203 | elif self.metric_value == "L" or self.metric_value == "low":
204 | self.availability_requirement_value = Metrics.cia_requirement.low
205 | else:
206 | if self.ar_metric != "set":
207 | self.availability_requirement_value = Metrics.cia_requirement.not_defined
208 |
209 | if self.metric_vector == "MAV":
210 | self.mav_metric = "set"
211 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
212 | self.attack_vector_value_modified = Metrics.attack_vector.not_defined
213 | elif self.metric_value == "N" or self.metric_value == "network":
214 | self.attack_vector_value_modified = Metrics.attack_vector.network
215 | elif self.metric_value == "A" or self.metric_value == "adjacent_network":
216 | self.attack_vector_value_modified = Metrics.attack_vector.adjacent_network
217 | elif self.metric_value == "L" or self.metric_value == "local":
218 | self.attack_vector_value_modified = Metrics.attack_vector.local
219 | elif self.metric_value == "P" or self.metric_value == "physical":
220 | self.attack_vector_value_modified = Metrics.attack_vector.physical
221 | else:
222 | if self.mav_metric != "set":
223 | self.attack_vector_value_modified = Metrics.attack_vector.not_defined
224 |
225 | if self.metric_vector == "MAC":
226 | self.mac_metric = "set"
227 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
228 | self.attack_complexity_value_modified = Metrics.attack_complexity.not_defined
229 | elif self.metric_value == "L" or self.metric_value == "low":
230 | self.attack_complexity_value_modified = Metrics.attack_complexity.low
231 | elif self.metric_value == "H" or self.metric_value == "high":
232 | self.attack_complexity_value_modified = Metrics.attack_complexity.high
233 | else:
234 | if self.mac_metric != "set":
235 | self.attack_complexity_value_modified = Metrics.attack_complexity.not_defined
236 |
237 | # Assigning the appropriate value to MPR depending on the Modified Scope. See the formula.
238 | if self.metric_vector == "MS":
239 | self.scope_value_modified = self.metric_value
240 | # getting the value of MPR vector from the original splitted vectors
241 | self.splitted_3 = self.vectors[16:17][0].split(':')
242 | self.metric_vector = self.splitted_3[0]
243 | self.metric_value = self.splitted_3[1]
244 | if self.scope_value_modified == "C" or self.scope_value_modified == "changed":
245 | self.scope_value_modified = "changed"
246 | if self.metric_vector == "MPR":
247 | self.mpr_metric = "set"
248 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
249 | self.privileges_required_value_modified = Metrics.privileges_required_changed.not_defined
250 | elif self.metric_value == "N" or self.metric_value == "none":
251 | self.privileges_required_value_modified = Metrics.privileges_required_changed.none
252 | elif self.metric_value == "L" or self.metric_value == "low":
253 | self.privileges_required_value_modified = Metrics.privileges_required_changed.low
254 | elif self.metric_value == "H" or self.metric_value == "high":
255 | self.privileges_required_value_modified = Metrics.privileges_required_changed.high
256 | else:
257 | if self.mpr_metric != "set":
258 | self.privileges_required_value_modified = Metrics.privileges_required_changed.not_defined
259 | else:
260 | self.scope_value_modified = "unchanged"
261 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
262 | self.privileges_required_value_modified = Metrics.privileges_required.not_defined
263 | elif self.metric_value == "N" or self.metric_value == "none":
264 | self.privileges_required_value_modified = Metrics.privileges_required.none
265 | elif self.metric_value == "L" or self.metric_value == "low":
266 | self.privileges_required_value_modified = Metrics.privileges_required.low
267 | elif self.metric_value == "H" or self.metric_value == "high":
268 | self.privileges_required_value_modified = Metrics.privileges_required.high
269 | else:
270 | raise Exception, "(MPR) Modified Privileges Required metric is not correct"
271 |
272 | if self.metric_vector == "MUI":
273 | self.mui_metric = "set"
274 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
275 | self.user_interaction_value_modified = Metrics.user_interaction.not_defined
276 | elif self.metric_value == "N" or self.metric_value == "none":
277 | self.user_interaction_value_modified = Metrics.user_interaction.none
278 | elif self.metric_value == "R" or self.metric_value == "required":
279 | self.user_interaction_value_modified = Metrics.user_interaction.required
280 | else:
281 | if self.mui_metric != "set":
282 | self.user_interaction_value_modified = Metrics.user_interaction.not_defined
283 |
284 | if self.metric_vector == "MC":
285 | self.mc_metric = "set"
286 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
287 | self.confidentiality_value_modified = Metrics.cia_impact.not_defined
288 | elif self.metric_value == "L" or self.metric_value == "low":
289 | self.confidentiality_value_modified = Metrics.cia_impact.low
290 | elif self.metric_value == "H" or self.metric_value == "high":
291 | self.confidentiality_value_modified = Metrics.cia_impact.high
292 | elif self.metric_value == "N" or self.metric_value == "none":
293 | self.confidentiality_value_modified = Metrics.cia_impact.none
294 | else:
295 | if self.mc_metric != "set":
296 | self.confidentiality_value_modified = Metrics.cia_impact.not_defined
297 |
298 | if self.metric_vector == "MI":
299 | self.mi_metric = "set"
300 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
301 | self.integrity_value_modified = Metrics.attack_vector.not_defined
302 | elif self.metric_value == "L" or self.metric_value == "low":
303 | self.integrity_value_modified = Metrics.cia_impact.low
304 | elif self.metric_value == "H" or self.metric_value == "high":
305 | self.integrity_value_modified = Metrics.cia_impact.high
306 | elif self.metric_value == "N" or self.metric_value == "none":
307 | self.integrity_value_modified = Metrics.cia_impact.none
308 | else:
309 | if self.mi_metric != "set":
310 | self.integrity_value_modified = Metrics.cia_impact.not_defined
311 |
312 | if self.metric_vector == "MA":
313 | self.ma_metric = "set"
314 | if self.metric_value == "X" or self.metric_value == "not_defined" or self.metric_value == "not defined":
315 | self.availability_value_modified = Metrics.cia_impact.not_defined
316 | elif self.metric_value == "L" or self.metric_value == "low":
317 | self.availability_value_modified = Metrics.cia_impact.low
318 | elif self.metric_value == "H" or self.metric_value == "high":
319 | self.availability_value_modified = Metrics.cia_impact.high
320 | elif self.metric_value == "N" or self.metric_value == "none":
321 | self.availability_value_modified = Metrics.cia_impact.none
322 | else:
323 | if self.ma_metric != "set":
324 | self.availability_value_modified = Metrics.cia_impact.not_defined
325 |
326 | return
327 |
328 | def cvss_base_score(self):
329 | """ call the CVSS v3 Base (in order exploitability then impact then base).
330 | :return: the CVSS v3 Base score value with its risk level
331 | """
332 | self.get_vectors()
333 | self.exploitability_sub_score_value = exploitability_sub_score(self.attack_vector_value,
334 | self.attack_complexity_value,
335 | self.privileges_required_value,
336 | self.user_interaction_value)
337 |
338 | self.impact_sub_score_value = impact_sub_score(self.availability_value, self.confidentiality_value,
339 | self.integrity_value)
340 |
341 | self.cvss_base_score_value = cvss_base_formula(self.impact_sub_score_value, self.scope_value,
342 | self.exploitability_sub_score_value)
343 |
344 | self.cvss_base_risk_level = self.risk_score(self.cvss_base_score_value)
345 |
346 | return (self.cvss_base_score_value, self.cvss_base_risk_level)
347 |
348 | def cvss_temporal_score(self):
349 | """ call the CVSS v3 Temporal formula. The CVSS base score is required but already calculated.
350 | :return: the CVSS v3 Temporal score value with its risk level
351 | """
352 |
353 | self.cvss_temporal_score_value = cvss_temporal_formula(self.cvss_base_score_value,
354 | self.exploit_code_maturity_value,
355 | self.remediation_level_value,
356 | self.report_confidence_value)
357 |
358 | self.cvss_temporal_risk_level = self.risk_score(self.cvss_temporal_score_value)
359 |
360 | return (self.cvss_temporal_score_value, self.cvss_temporal_risk_level)
361 |
362 | def cvss_environmental_score(self):
363 | """ call the CVSS v3 Environmental formula (in order exp. sub score, impact sub score)
364 | :return: the CVSS v3 Environmental score value with its risk level
365 | """
366 | self.exploitability_sub_score_value_modified = exploitability_sub_score_modified(
367 | self.attack_vector_value_modified,
368 | self.attack_complexity_value_modified,
369 | self.privileges_required_value_modified,
370 | self.user_interaction_value_modified)
371 |
372 | self.impact_sub_score_value_modified = impact_sub_score_modified(self.availability_value_modified,
373 | self.confidentiality_value_modified,
374 | self.integrity_value_modified,
375 | self.confidentiality_requirement_value,
376 | self.integrity_requirement_value,
377 | self.availability_requirement_value)
378 |
379 | self.cvss_environmental_value = cvss_environmental_formula(self.impact_sub_score_value_modified,
380 | self.exploitability_sub_score_value_modified,
381 | self.exploit_code_maturity_value,
382 | self.remediation_level_value,
383 | self.report_confidence_value,
384 | self.scope_value_modified)
385 |
386 | self.cvss_environmental_risk_level = self.risk_score(self.cvss_environmental_value)
387 |
388 | return (self.cvss_environmental_value, self.cvss_environmental_risk_level)
389 |
390 | def risk_score(self, score):
391 | """
392 | :param score: risk values
393 | :return: the qualitative risk rating values from none to critical
394 | """
395 | if score == float(0):
396 | self.risk_level = "None"
397 | elif score >= float(0.1) and score <= float(3.9):
398 | self.risk_level = "Low"
399 | elif score >= float(4.0) and score <= float(6.9):
400 | self.risk_level = "Medium"
401 | elif score >= float(7.0) and score <= float(8.9):
402 | self.risk_level = "High"
403 | elif score >= float(9.0) and score <= float(10.0):
404 | self.risk_level = "Critical"
405 | return self.risk_level
406 |
--------------------------------------------------------------------------------