Saturday, July 14, 2007

CVSS 2.0 Calculator

pyCVSS_calc.py
----------------

"""
Implements Common Vulnerability Scoring System Version 2 Calculator
(CVSS v2) Calculator.

Functions:
verify_metric_value
cvss_base_score
cvss_temp_score
cvss_env_score
get_risk_factor
gen_cvss_report
check_proceed
read_metric_value

Author: Hansa Date:7/14/07
"""

import sys

# Predefined Standard Values

# Base Score Metric
# Base AV:[L,A,N]/AC:[H,M,L]/Au:[M,S,N]/C:[N,P,C]/I:[N,P,C]/A:[N,P,C]
AV = {'L': ['REQUIRES LOCAL ACCESS', 0.395],
'A': ['ADJACENT NETWORK ACCESSIBLE', 0.646],
'N':['NETWORK ACCESSIBLE', 1.0]}
AC = {'H': ['HIGH', 0.35],
'M':['MEDIUM', 0.61],
'L': ['LOW', 0.71]}
AU = {'M': ['REQUIRES MULTIPLE INSTANCES OF AUTHENTICATION', 0.45],
'S': ['REQUIRES SINGLE INSTANCE OF AUTHENTICATION', 0.56],
'N': ['REQUIRES NO AUNTHENTICATION', 0.704]}
CI = {'N': ['NONE', 0.0],
'P': ['PARTIAL', 0.275],
'C': ['COMPLETE', 0.660]}
II = {'N': ['NONE', 0.0],
'P': ['PARTIAL', 0.275],
'C': ['COMPLETE', 0.660]}
AI = {'N': ['NONE', 0.0],
'P': ['PARTIAL', 0.275],
'C': ['COMPLETE', 0.660]}

# Temporal Score Metric
# Temporal E:[U,POC,F,H,ND]/RL:[OF,TF,W,U,ND]/RC:[UC,UR,C,ND]
EXP = {'U': ['UNPROVEN', 0.85],
'POC': ['PROOF_OF_CONCEPT', 0.9],
'F': ['FUNCTIONAL', 0.95],
'H': ['HIGH', 1.0],
'ND': ['NOT DEFINED', 1.0]}
RL = {'OF': ['OFFICIAL_FIX', 0.87],
'TF': ['TEMPORARY_FIX', 0.90],
'W': ['WORKAROUND', 0.95],
'U': ['UNAVAILABLE', 1.0],
'ND': ['NOT DEFINED', 1.0]}
RC = {'UC': ['UNCONFIRMED', 0.90],
'UR': ['UNCORROBORATED', 0.95],
'C': ['CONFIRMED', 1.0],
'ND': ['NOT DEFINED', 1.0]}

# Environmental Score Metric
#Environmental CDP:[N,L,LM,MH,H,ND]/TD:[N,L,M,H,ND]/CR:[L,M,H,ND]/IR:[L,M,H,ND]/AR:[L,M,H,ND]
CDP = {'N': ['NONE', 0],
'L': ['LOW', 0.1],
'LM': ['LOW-MEDIUM', 0.3],
'MH': ['MEDIUM-HIGH', 0.4],
'H': ['HIGH', 0.5],
'ND': ['NOT DEFINED', 0]}
TD = {'N': ['NONE', 0],
'L': ['LOW', 0.25],
'M': ['MEDIUM', 0.75],
'H': ['HIGH', 1.0],
'ND': ['NOT DEFINED', 1.0]}
CR = {'L': ['LOW', 0.5],
'M': ['MEDIUM', 1.0],
'H': ['HIGH', 1.51],
'ND': ['NOT DEFINED', 1.0]}
IR = {'L': ['LOW', 0.5],
'M': ['MEDIUM', 1.0],
'H': ['HIGH', 1.51],
'ND': ['NOT DEFINED', 1.0]}
AR = {'L': ['LOW', 0.5],
'M': ['MEDIUM', 1.0],
'H': ['HIGH', 1.51],
'ND': ['NOT DEFINED', 1.0]}

# Index
MN = 0 # Name the Metric
MC = 1 # Constant Value of Metric

# Initialize input parameters
(av, ac, au, ci, ii, ai, exp, rl, rc, cdp, td, cr, ir, ar) = [None]*14

def verify_metric_value(mc, mn):
"""Check if valid metric value is given."""

# check for valid data type (string)
if type(mc) != str:
print "ERROR: Accepts only string values"
return None

# check for empty string value
if mc == '':
print "ERROR: Empty value"
return None

# normalize the value
mc = mc.upper()

# quit execution when user enter 'Q'
if mc == 'Q':
sys.exit(0)

# validate the string values w.r.t standard predefined values
if mn == 'AV' and not AV.has_key(mc) or \
mn == 'AC' and not AC.has_key(mc) or \
mn == 'AU' and not AU.has_key(mc) or \
mn == 'C' and not CI.has_key(mc) or \
mn == 'I' and not II.has_key(mc) or \
mn == 'A' and not AI.has_key(mc) or \
mn == 'E' and not EXP.has_key(mc) or \
mn == 'RL' and not RL.has_key(mc) or \
mn == 'RC' and not RC.has_key(mc) or \
mn == 'CDP' and not CDP.has_key(mc) or \
mn == 'TD' and not TD.has_key(mc) or \
mn == 'CR' and not CR.has_key(mc) or \
mn == 'IR' and not IR.has_key(mc) or \
mn == 'AR' and not AR.has_key(mc):
print "ERROR: Incorrect option for %s metric" % (mn)
return None

return mc

def f(impact_value):
"""Evaluates impact value"""

if impact_value == 0:
return 0
else:
return 1.176

def cvss_base_score():
"""Evaluates Base Score"""

global base_score
global exploitability

try:
impact = 10.41*(1-(1-CI[ci][MC])*(1-II[ii][MC])*(1-AI[ai][MC]))
exploitability = round((20*AV[av][MC]*AC[ac][MC]*AU[au][MC]), 1)
base_score = round((((0.6*impact)+(0.4*exploitability)-1.5)*f(impact)),
1)
#print "DEBUG: base_score", base_score
except Exception, err:
print "ERROR: ", err
return None

def cvss_temp_score():
"""Evaluates Temporal Score"""

global temp_score
global base_score

try:
temp_score = round(base_score*EXP[exp][MC]*RL[rl][MC]*RC[rc][MC], 1)
#print "DEBUG: temp_score", temp_score
except Exception, err:
print "ERROR: ", err
return None

def cvss_env_score():
"""Evaluates Environmental Score"""

global exploitability
global env_score

try:
adj_impact = round(min(10,10.41*(1-(1-CI[ci][MC]*CR[cr][MC])
*(1-II[ii][MC]*IR[ir][MC])
*(1-AI[ai][MC]*AR[ar][MC]))), 1)
#print "DEBUG: adj_impact", adj_impact
adj_base = round(((0.6*adj_impact)+(0.4*exploitability)-1.5)*
f(adj_impact), 1)
#print "DEBUG: adj_base", adj_base
adj_temp = round(adj_base*EXP[exp][MC]*RL[rl][MC]*RC[rc][MC], 1)
#print "DEBUG: adj_temp", adj_temp
env_score = round((adj_temp+(10-adj_temp)*CDP[cdp][MC])*TD[td][MC] ,1)
#print "DEBUG: env_score", env_score
except Exception, err:
print "ERROR: ", err
return None

def get_risk_factor(cvss_score):
"""Find the risk factor base on temp score"""

risk = ""
if cvss_score > 0 and cvss_score <= 2:
risk = "Low"
elif cvss_score > 2 and cvss_score <= 5:
risk = "Medium"
elif cvss_score > 5 and cvss_score <= 8:
risk = "High"
elif cvss_score > 8 and cvss_score <= 10:
risk = "Critical"
else:
print "ERROR: Invalid Temporal Score"
return None

#print "\n\nDEBUG: Mappings for Risk Factors \n\ #
# >0-2 : Low \n\
# >2-6 : Medium \n\
# >6-9 : High \n\
# >9-10 : Critical"
return risk

def gen_cvss_report():
"""Generate CVSS report based on given metric values"""

global bscore_vector
global tscore_vector
global escore_vector
global base_score
global temp_score
global env_score

cvssreport = ""
vectorreport = ""

if base_score == None:
print "ERROR: Invalid base score found"

#print "\n\nDEBUG: Generating CVSS Score report..."
if base_score != None and bscore_vector != []:
basescore_vector = ''
for name, value in bscore_vector:
basescore_vector = basescore_vector + '%s:%s/' % (name,value)
basescore_vector = '(%s)' % (basescore_vector.rstrip("/"))
#print "\nDEBUG: CVSS Base Score Vector: ", basescore_vector
vectorreport = vectorreport + "\nCVSS Base Score & Vector: %s = %s\n" % \
(basescore_vector, base_score)
cvssreport = cvssreport + "\nCVSS Score Metric Values: \n\
ACCESS_VECTOR = %s \n\
ACCESS_COMPLEXITY = %s \n\
AUTHENTICATION = %s \n\
CONFIDENTIALITY_IMPACT = %s \n\
INTEGRITY_IMPACT = %s \n\
AVAILABILITY_IMPACT = %s \n\
" % (AV[av][MN], AC[ac][MN], AU[au][MN], CI[ci][MN],
II[ii][MN], AI[ai][MN])

if temp_score != None:
tempscore_vector = ''
for name, value in tscore_vector:
tempscore_vector = tempscore_vector + '%s:%s/' % (name,value)
tempscore_vector = '(%s)' % (tempscore_vector.rstrip("/"))
#print "\nDEBUG: CVSS Temporal Score Vector: ", tempscore_vector
cvssreport = cvssreport + "EXPLOITABILITY = %s\n\
REMEDIATION_LEVEL = %s \n\
REPORT_CONFIDENCE = %s \n\
" % (EXP[exp][MN], RL[rl][MN], RC[rc][MN])
vectorreport = vectorreport + "CVSS Temporal Score & Vector: %s = %s\n" % \
(tempscore_vector, temp_score)

if env_score != None:
envscore_vector = ''
for name, value in escore_vector:
envscore_vector = envscore_vector + '%s:%s/' % (name,value)
envscore_vector = '(%s)' % (envscore_vector.rstrip("/"))
#print "\nDEBUG: CVSS Environmental Score Vector: ", envscore_vector
cvssreport = cvssreport + "COLLATERAL DAMAGE POTENTIAL = %s \n\
TARGET DISTRIBUTION = %s \n\
CONFIDENTIALITY REQUIREMENT = %s \n\
INTEGRITY REQUIREMENT = %s \n\
AVAILABILITY REQUIREMENT = %s \n\
" % (CDP[cdp][MN], TD[td][MN], CR[cr][MN], IR[ir][MN],
AR[ar][MN])
vectorreport = vectorreport + "CVSS Environmental Score & Vector: %s = %s\n" % \
(envscore_vector, env_score)

cvssreport = cvssreport + vectorreport
print cvssreport

if env_score != None:
print "Risk Factor : ", get_risk_factor(env_score)
elif temp_score != None:
print "Risk Factor : ", get_risk_factor(temp_score)
elif base_score != None:
print "Risk Factor : ", get_risk_factor(base_score)
else:
print "\nERROR: No score found."

def check_proceed():
"""Check if you want to continue calculation or not."""

check = None

while check == None:
print "Want to Continue? Yes:Y/No:N"
check = raw_input().upper()

if check == "N":
gen_cvss_report()
sys.exit(0)
elif check == "Y":
pass
else:
print "ERROR: Invalid Option. Type Y for Yes or N for No"
check = None

def read_metric_value(print_txt, metric_value, metric_name, score_vector):
"""Read input parameters (CVSS score metric values)"""

while metric_value == None:
print print_txt
metric_value = verify_metric_value(raw_input(), metric_name)
if(metric_value != None):
score_vector.append([metric_name, metric_value])
return metric_value, score_vector

# Main
if __name__ == '__main__':
exploitability = 0.0
base_score = None
temp_score = None
env_score = None
bscore_vector = []
tscore_vector = []
escore_vector = []

print "CVSS v2 Calculator\n" + \
"\nNote:\nPlease choose the corresponding metric values." + \
"\nMetric values are case in-sensitive. " + \
"\nEnter 'Q/q' to quit the execution.\n"

# Read input values
av, bscore_vector = read_metric_value("\nChoose metric value for " + \
"ACCESS_VECTOR.\nOptions are REQUIRES LOCAL ACCESS:L | " + \
"ADJACENT NETWORK ACCESSIBLE:A | NETWORK ACCESSIBLE:N",
av, "AV", bscore_vector)
ac, bscore_vector = read_metric_value("\nChoose metric value for ACCESS_" + \
"COMPLEXITY = HIGH:H | MEDIUM:M | LOW:L", ac, "AC",
bscore_vector)
au, bscore_vector = read_metric_value("\nChoose metric value for " + \
"AUTHENTICATION.\nOptions are REQUIRES MULTIPLE " + \
"INSTANCES OF AUTHENTICATION:M | REQUIRES SINGLE " + \
"INSTANCE OF AUTHENTICATION:S | REQUIRES NO " + \
"AUTHENTICATION:N", au, "AU", bscore_vector)
ci, bscore_vector = read_metric_value("\nChoose metric value for " + \
"CONFIDENTIALITY_IMPACT.\nOptions are NONE:N | PARTIAL:P" + \
"| COMPLETE:C", ci, "CI", bscore_vector)
ii, bscore_vector = read_metric_value("\nChoose metric value for " + \
"INTEGRITY_IMPACT.\nOptions are NONE:N | PARTIAL:P | " + \
"COMPLETE:C",ii, "II", bscore_vector)
ai, bscore_vector = read_metric_value("\nChoose metric value for " + \
"AVAILABILITY_IMPACT.\nOptions are NONE:N | PARTIAL:P |" + \
"COMPLETE:C", ai, "AI", bscore_vector)

#print "DEBUG: Calculating Base Score ...",
cvss_base_score()
print "Base Score :", base_score
check_proceed()

exp, tscore_vector = read_metric_value("\nChoose metric value for " + \
"EXPLOITABILITY.\nOptions are UNPROVEN:U | " + \
"PROOF_OF_CONCEPT:POC | FUNCTIONAL:F | HIGH:H | " + \
"NOT DEFINED:ND", exp, "E", tscore_vector)
rl, tscore_vector = read_metric_value("\nChoose metric value for " + \
"REMEDIATION_LEVEL.\nOptions are OFFICIAL_FIX:OF | " + \
"TEMPORARY_FIX:TF | WORKAROUND:W | UNAVAILABLE:U | " + \
"NOT DEFINED:ND", rl, "RL", tscore_vector)
rc, tscore_vector = read_metric_value("\nChoose metric value for " + \
"REPORT_CONFIDENCE.\nOptions are UNCONFIRMED:UC | " + \
"UNCORROBORATED:UR | CONFIRMED:C | NOT DEFINED:ND", rc,
"RC", tscore_vector)

#print "DEBUG: Calculating Temporal Score ..."
cvss_temp_score()
print "Temporal Score :", temp_score
check_proceed()

cdp, escore_vector = read_metric_value("\nChoose metric value for " + \
"COLLATERAL_DAMAGE_POTENTIAL.\nOptions are NONE:N |" + \
"LOW:L | LOW-MEDIUM:LM | MEDIUM-HIGH:MH| HIGH:H | " + \
"NOT DEFINED:ND", cdp, "CDP", tscore_vector)
td, escore_vector = read_metric_value("\nChoose metric value for " + \
"TARGET_DISTRIBUTION.\nOptions are NONE:N | LOW:L | " + \
"MEDIUM:M | HIGH:H | NOT DEFINED:ND", td, "TD",
tscore_vector)
cr, escore_vector = read_metric_value("\nChoose metric value for " + \
"CONF_REQ.\nOptions are LOW:L | MEDIUM:M | HIGH:H |" + \
"NOT DEFINED:ND", cr, "CR", escore_vector)
ir, escore_vector = read_metric_value("\nChoose metric value for " + \
"INTEG_REQ.\nOptions are LOW:L | MEDIUM:M | HIGH:H" + \
"| NOT DEFINED:ND", ir, "IR", escore_vector)
ar, escore_vector = read_metric_value("\nChoose metric value for " + \
"INTEG_REQ.\nOptions are LOW:L | MEDIUM:M | HIGH:H |" + \
"NOT DEFINED:ND", ar, "AR", escore_vector)

#print "DEBUG: Calculating Environmental Score ... "
cvss_env_score()
print "Environmental Score :", env_score

# generate complete report
gen_cvss_report()

No comments: