forked from atorlee/SUSE-Manager-Tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cve_report.py
executable file
·201 lines (183 loc) · 6.77 KB
/
cve_report.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env python3
#
# CVEReport
#
# (c) 2019 SUSE Linux GmbH, Germany.
# GNU Public License. No warranty. No support
# For question/suggestions/bugs mail: [email protected]
#
# Version: 2019-02-12
#
# Created by: SUSE Michael Brookhuis
#
# This script will generate an comma-delimited file with system effected.
#
# Releases:
# 2019-02-12 M.Brookhuis - initial release.
#
#
#
#
"""
CVE report.
"""
import os
import argparse
from argparse import RawTextHelpFormatter
import datetime
import smtools
__smt = None
def _create_cve(data, path, header):
"""
Create CVE data.
"""
with open(path, "w") as fhcve:
if not data:
fhcve.write("NO CVE\n") # TODO: Should it be a broken data inside after all?
else:
fhcve.write("{}\n".format(header))
for row in data:
fhcve.write("{}\n".format(";".join(row)))
def create_file_cve(cve_data, fn):
"""
Create CVE data.
"""
_create_cve(data=cve_data, path=fn,
header="System Name;CVE;Patch-Name;Patch available,channel containing patch;Packages included")
def create_file_cve_reverse(cve_data, fn):
"""
Create (reverse?) CVE data.
"""
_create_cve(data=cve_data, path=fn, header="System Name;CVE")
def logfile_present(path):
"""
Check type for the existing file
"""
if not os.path.isfile(path):
raise argparse.ArgumentTypeError("Not a valid file: '{0}'.".format(path))
return path
def get_cve_content(args):
"""
Get CVE content.
"""
smt.log_info("")
smt.log_info("Start {}".format(datetime.datetime.now()))
smt.log_info("")
smt.log_info("Given list of CVEs: {}".format(args.cve))
smt.log_info("")
smt.suman_login()
cve_data = []
for i in args.cve.split(','):
cve_data.append(i)
return cve_data
# noinspection PyPep8
def get_cve_data(args):
"""
Get CVE data.
"""
cve_data_collected = []
for cve in get_cve_content(args):
if not args.reverse:
# noinspection PyPep8,PyBroadException
try:
cve_list = smt.client.audit.listSystemsByPatchStatus(smt.session, cve, ["AFFECTED_PATCH_INAPPLICABLE",
"AFFECTED_PATCH_APPLICABLE"])
except:
cve_list = []
if not cve_list:
smt.log_warning("Given CVE {} does not exist.".format(cve))
break
else:
smt.log_info("Processing CVE {}.".format(cve))
for cve_system in cve_list:
cve_data = []
# noinspection PyBroadException
try:
cve_data.append(smt.client.system.getName(smt.session, cve_system.get("system_id")).get("name"))
except:
smt.log_error('unable to get hostname for system with ID {}.'.format(cve_system.get("system_id")))
break
cve_data.append(cve)
adv_list = ""
pack_list = ""
for adv in cve_system.get('errata_advisories'):
if adv_list:
adv_list = adv_list + ", " + adv
else:
adv_list = adv
cve_packages = None
# noinspection PyPep8,PyBroadException
try:
cve_packages = smt.client.errata.listPackages(smt.session, adv)
except:
print("unable to find packages")
for package in cve_packages:
pack = package.get('name') + "-" + package.get('version') + "-" + package.get(
'release') + "-" + package.get('arch_label')
if pack_list:
pack_list = pack_list + ", " + pack
else:
pack_list = pack
cve_data.append(adv_list)
cve_data.append(cve_system.get('patch_status'))
chan_list = ""
for chan in cve_system.get("channel_labels"):
if chan_list:
chan_list = chan_list + ", " + chan
else:
chan_list = chan
cve_data.append(chan_list)
cve_data.append(pack_list)
cve_data_collected.append(cve_data)
smt.log_info("Completed.")
else:
# noinspection PyPep8,PyBroadException
try:
cve_list = smt.client.audit.listSystemsByPatchStatus(smt.session, cve, ["NOT_AFFECTED", "PATCHED"])
except:
cve_list = []
if not cve_list:
smt.log_warning("Given CVE {} does not exist.".format(cve))
break
else:
smt.log_info("Processing CVE {}.".format(cve))
for cve_system in cve_list:
cve_data = []
# noinspection PyPep8,PyBroadException
try:
cve_data.append(smt.client.system.getName(smt.session, cve_system.get("system_id")).get("name"))
except:
smt.log_error("unable to get hostname for system with ID %{}".format(cve_system.get("system_id")))
break
cve_data.append(cve)
cve_data_collected.append(cve_data)
smt.log_info("Completed.")
return cve_data_collected
def main():
"""
Main function.
"""
global smt
smt = smtools.SMTools("cve_report")
parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description="CVE report tool")
parser.add_argument("-c", "--cve", help="list of CVEs to be checked, comma delimeted, no spaces", required=True)
parser.add_argument("-r", "--reverse", action="store_true", default=0,
help="list systems that have the CVE installed")
parser.add_argument("-f", "--filename",
help="filename the data should be writen in. If no path is given it will be stored in directory where the script has been started.",
required=True, type=logfile_present)
parser.add_argument('--version', action='version', version='%(prog)s 0.0.1, October 20, 2017')
args = parser.parse_args()
if args.filename:
cve_data = get_cve_data(args)
if not args.reverse:
create_file_cve(cve_data, args.filename)
else:
create_file_cve_reverse(cve_data, args.filename)
smt.log_info("Result can be found in file: {}".format(args.filename))
smt.suman_logout()
smt.close_program()
else:
parser.print_help()
if __name__ == "__main__":
SystemExit(main())