Added jira section to config file and fail check for config variable (#105)
* clean OS X .DS_Store files * fix nessus end of line carriage, added JIRA args * JIRA module fully working * jira module working with nessus * added check on already existing jira config, update README * qualys_vm<->jira working, qualys_vm database entries with qualys_vm, improved checks * JIRA module updates ticket's assets and comments update * added JIRA auto-close function for resolved vulnerabitilies * fix if components variable empty issue * fix creation of new ticket after updating existing one * final fixes, added extra line in template * added vulnerability criticality as label in order to be able to filter * jira module gets now minimum criticality from config file * added jira config to frameworks_example.ini * fail check for config variable in case it is left empty
This commit is contained in:

committed by
Austin Taylor

parent
4422db586d
commit
9383c12495
@ -87,3 +87,22 @@ verbose=true
|
|||||||
; proxy authentication
|
; proxy authentication
|
||||||
#proxy_username = proxyuser
|
#proxy_username = proxyuser
|
||||||
#proxy_password = proxypass
|
#proxy_password = proxypass
|
||||||
|
|
||||||
|
[jira]
|
||||||
|
hostname = jira-host
|
||||||
|
username = username
|
||||||
|
password = password
|
||||||
|
write_path = /opt/VulnWhisperer/data/jira/
|
||||||
|
db_path = /opt/VulnWhisperer/data/database
|
||||||
|
verbose = true
|
||||||
|
|
||||||
|
#Sample jira report scan, will automatically be created for existent scans
|
||||||
|
#[jira.qualys_vuln.test_scan]
|
||||||
|
#source = qualys_vuln
|
||||||
|
#scan_name = Test Scan
|
||||||
|
#jira_project = PROJECT
|
||||||
|
; if multiple components, separate by "," = None
|
||||||
|
#components =
|
||||||
|
; minimum criticality to report (low, medium, high or critical) = None
|
||||||
|
#min_critical_to_report = high
|
||||||
|
|
||||||
|
@ -986,6 +986,12 @@ class vulnWhispererJIRA(vulnWhispererBase):
|
|||||||
#cleaning empty array from ''
|
#cleaning empty array from ''
|
||||||
if not components[0]:
|
if not components[0]:
|
||||||
components = []
|
components = []
|
||||||
|
|
||||||
|
min_critical = self.config.get(jira_section,'min_critical_to_report')
|
||||||
|
if not min_critical:
|
||||||
|
self.vprint('{error} - "min_critical_to_report" variable on config file is empty.'.format(error=bcolors.FAIL))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
#datafile path
|
#datafile path
|
||||||
filename = self.get_latest_results(source, scan_name)
|
filename = self.get_latest_results(source, scan_name)
|
||||||
|
|
||||||
@ -998,21 +1004,24 @@ class vulnWhispererJIRA(vulnWhispererBase):
|
|||||||
self.vprint('{error} - Scan file path "{scan_name}" for source "{source}" has not been found.'.format(error=bcolors.FAIL, scan_name=scan_name, source=source))
|
self.vprint('{error} - Scan file path "{scan_name}" for source "{source}" has not been found.'.format(error=bcolors.FAIL, scan_name=scan_name, source=source))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
return project, components, fullpath
|
return project, components, fullpath, min_critical
|
||||||
|
|
||||||
|
|
||||||
def parse_nessus_vulnerabilities(self, fullpath, source, scan_name):
|
def parse_nessus_vulnerabilities(self, fullpath, source, scan_name, min_critical):
|
||||||
|
|
||||||
vulnerabilities = []
|
vulnerabilities = []
|
||||||
|
|
||||||
# we need to parse the CSV
|
# we need to parse the CSV
|
||||||
excluded_risks = ['None','Low']
|
risks = ['none', 'low', 'medium', 'high', 'critical']
|
||||||
|
min_risk = int([i for i,x in enumerate(risks) if x == min_critical][0])
|
||||||
|
|
||||||
df = pd.read_csv(fullpath, delimiter=',')
|
df = pd.read_csv(fullpath, delimiter=',')
|
||||||
|
|
||||||
#nessus fields we want - ['Host','Protocol','Port', 'Name', 'Synopsis', 'Description', 'Solution', 'See Also']
|
#nessus fields we want - ['Host','Protocol','Port', 'Name', 'Synopsis', 'Description', 'Solution', 'See Also']
|
||||||
for index in range(len(df)):
|
for index in range(len(df)):
|
||||||
# filtering vulnerabilities by criticality, discarding low risk
|
# filtering vulnerabilities by criticality, discarding low risk
|
||||||
if df.loc[index]['Risk'] in excluded_risks:
|
to_report = int([i for i,x in enumerate(risks) if x == df.loc[index]['Risk'].lower()][0])
|
||||||
|
if to_report < min_risk:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not vulnerabilities or df.loc[index]['Name'] not in [entry['title'] for entry in vulnerabilities]:
|
if not vulnerabilities or df.loc[index]['Name'] not in [entry['title'] for entry in vulnerabilities]:
|
||||||
@ -1044,19 +1053,19 @@ class vulnWhispererJIRA(vulnWhispererBase):
|
|||||||
|
|
||||||
return vulnerabilities
|
return vulnerabilities
|
||||||
|
|
||||||
def parse_qualys_vuln_vulnerabilities(self, fullpath, source, scan_name):
|
def parse_qualys_vuln_vulnerabilities(self, fullpath, source, scan_name, min_critical):
|
||||||
#parsing of the qualys vulnerabilities schema
|
#parsing of the qualys vulnerabilities schema
|
||||||
#parse json
|
#parse json
|
||||||
vulnerabilities = []
|
vulnerabilities = []
|
||||||
minimum_criticality_reported = 4
|
|
||||||
|
|
||||||
risks = ['info', 'low', 'medium', 'high', 'critical']
|
risks = ['info', 'low', 'medium', 'high', 'critical']
|
||||||
|
min_risk = int([i for i,x in enumerate(risks) if x == min_critical][0])
|
||||||
|
|
||||||
data=[json.loads(line) for line in open(fullpath).readlines()]
|
data=[json.loads(line) for line in open(fullpath).readlines()]
|
||||||
|
|
||||||
#qualys fields we want - []
|
#qualys fields we want - []
|
||||||
for index in range(len(data)):
|
for index in range(len(data)):
|
||||||
if int(data[index]['risk']) < 4:
|
if int(data[index]['risk']) < min_risk:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not vulnerabilities or data[index]['plugin_name'] not in [entry['title'] for entry in vulnerabilities]:
|
if not vulnerabilities or data[index]['plugin_name'] not in [entry['title'] for entry in vulnerabilities]:
|
||||||
@ -1103,7 +1112,7 @@ class vulnWhispererJIRA(vulnWhispererBase):
|
|||||||
|
|
||||||
return values
|
return values
|
||||||
|
|
||||||
def parse_vulnerabilities(self, fullpath, source, scan_name):
|
def parse_vulnerabilities(self, fullpath, source, scan_name, min_critical):
|
||||||
#TODO: SINGLE LOCAL SAVE FORMAT FOR ALL SCANNERS
|
#TODO: SINGLE LOCAL SAVE FORMAT FOR ALL SCANNERS
|
||||||
#JIRA standard vuln format - ['source', 'scan_name', 'title', 'diagnosis', 'consequence', 'solution', 'ips', 'references']
|
#JIRA standard vuln format - ['source', 'scan_name', 'title', 'diagnosis', 'consequence', 'solution', 'ips', 'references']
|
||||||
|
|
||||||
@ -1112,17 +1121,17 @@ class vulnWhispererJIRA(vulnWhispererBase):
|
|||||||
|
|
||||||
def jira_sync(self, source, scan_name):
|
def jira_sync(self, source, scan_name):
|
||||||
|
|
||||||
project, components, fullpath = self.get_env_variables(source, scan_name)
|
project, components, fullpath, min_critical = self.get_env_variables(source, scan_name)
|
||||||
|
|
||||||
vulnerabilities = []
|
vulnerabilities = []
|
||||||
|
|
||||||
#***Nessus parsing***
|
#***Nessus parsing***
|
||||||
if source == "nessus":
|
if source == "nessus":
|
||||||
vulnerabilities = self.parse_nessus_vulnerabilities(fullpath, source, scan_name)
|
vulnerabilities = self.parse_nessus_vulnerabilities(fullpath, source, scan_name, min_critical)
|
||||||
|
|
||||||
#***Qualys VM parsing***
|
#***Qualys VM parsing***
|
||||||
if source == "qualys_vuln":
|
if source == "qualys_vuln":
|
||||||
vulnerabilities = self.parse_qualys_vuln_vulnerabilities(fullpath, source, scan_name)
|
vulnerabilities = self.parse_qualys_vuln_vulnerabilities(fullpath, source, scan_name, min_critical)
|
||||||
|
|
||||||
#***JIRA sync***
|
#***JIRA sync***
|
||||||
if vulnerabilities:
|
if vulnerabilities:
|
||||||
|
Reference in New Issue
Block a user