-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNessus_file_parser.py
344 lines (282 loc) · 13.5 KB
/
Nessus_file_parser.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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
import os
import xml.etree.ElementTree as ET
from collections import defaultdict
def parse_nessus_file(file_path):
vulnerabilities = []
try:
tree = ET.parse(file_path)
root = tree.getroot()
for report_host in root.findall(".//ReportHost"):
host_ip = report_host.get("name")
for item in report_host.findall(".//ReportItem"):
risk_factor_element = item.find(".//risk_factor")
if risk_factor_element is not None:
risk_factor = risk_factor_element.text.strip()
else:
risk_factor = "N/A"
vulnerability_name = item.get("pluginName")
# Collect CVE IDs
cve_elements = item.findall(".//cve")
cve_ids = [cve.text.strip() for cve in cve_elements] if cve_elements else []
# Collect CWE IDs
cwe_elements = item.findall(".//cwe")
cwe_ids = [cwe.text.strip() for cwe in cwe_elements] if cwe_elements else []
# Combine CVE and CWE IDs
combined_ids = cve_ids + cwe_ids if cve_ids or cwe_ids else ["N/A"]
solution = item.find(".//solution").text.strip() if item.find(".//solution") is not None else "N/A"
# Collect references and format them
reference_elements = item.findall(".//see_also")
references = [ref.text.strip() for ref in reference_elements] if reference_elements else []
reference = ", ".join(references) if references else "N/A"
description = item.find(".//description").text.strip() if item.find(".//description") is not None else "N/A"
port = item.get('port', '0')
ip_port = host_ip if port == '0' else f"{host_ip} (Port No.: {port})"
# Adjust the severity for specific vulnerabilities
if vulnerability_name == "SSLv3 Padding Oracle On Downgraded Legacy Encryption Vulnerability (POODLE)":
risk_factor = "Low"
elif vulnerability_name == "SSL Version 2 and 3 Protocol Detection":
risk_factor = "High"
if risk_factor in ["Critical", "High", "Medium", "Low"]:
vulnerabilities.append({
"IP(Port)": ip_port,
"Vulnerability Name": vulnerability_name,
"CVE/CWE IDs": ', '.join(combined_ids),
"Severity": risk_factor,
"Recommendation": solution,
"Reference": reference,
"Description": description
})
except Exception as e:
print("Error parsing Nessus file:", e)
# Sort the vulnerabilities by severity: Critical, High, Medium, Low
severity_order = {"Critical": 1, "High": 2, "Medium": 3, "Low": 4}
vulnerabilities.sort(key=lambda x: severity_order.get(x["Severity"], 5))
# Merge vulnerabilities based on vulnerability name
merged_vulnerabilities = merge_vulnerabilities(vulnerabilities)
return merged_vulnerabilities
def merge_vulnerabilities(vulnerabilities):
merged_vulnerabilities = defaultdict(lambda: {
"IPs": set(),
"Vulnerability Names": set(),
"CVE/CWE IDs": set(),
"Severity": None,
"Recommendation": None,
"Reference": None,
"Description": None
})
for vuln in vulnerabilities:
vulnerability_name = vuln["Vulnerability Name"]
# Check if the vulnerability name already exists in merged_vulnerabilities
if vulnerability_name in merged_vulnerabilities:
# Merge IP addresses, CVE/CWE IDs, and update other fields
merged_vulnerabilities[vulnerability_name]["IPs"].add(vuln["IP(Port)"])
merged_vulnerabilities[vulnerability_name]["CVE/CWE IDs"].update(vuln["CVE/CWE IDs"].split(', '))
merged_vulnerabilities[vulnerability_name]["Severity"] = vuln["Severity"]
if merged_vulnerabilities[vulnerability_name]["Recommendation"] is None:
merged_vulnerabilities[vulnerability_name]["Recommendation"] = vuln["Recommendation"]
if merged_vulnerabilities[vulnerability_name]["Reference"] is None:
merged_vulnerabilities[vulnerability_name]["Reference"] = vuln["Reference"]
if merged_vulnerabilities[vulnerability_name]["Description"] is None:
merged_vulnerabilities[vulnerability_name]["Description"] = vuln["Description"]
else:
# If the vulnerability name is not in merged_vulnerabilities, add new entry
merged_vulnerabilities[vulnerability_name]["IPs"].add(vuln["IP(Port)"])
merged_vulnerabilities[vulnerability_name]["Vulnerability Names"].add(vulnerability_name)
merged_vulnerabilities[vulnerability_name]["CVE/CWE IDs"].update(vuln["CVE/CWE IDs"].split(', '))
merged_vulnerabilities[vulnerability_name]["Severity"] = vuln["Severity"]
merged_vulnerabilities[vulnerability_name]["Recommendation"] = vuln["Recommendation"]
merged_vulnerabilities[vulnerability_name]["Reference"] = vuln["Reference"]
merged_vulnerabilities[vulnerability_name]["Description"] = vuln["Description"]
result = []
for vulnerability_name, merged_data in merged_vulnerabilities.items():
result.append({
"IP(Port)": ', '.join(merged_data["IPs"]),
"Vulnerability Name": vulnerability_name,
"CVE/CWE IDs": ', '.join(merged_data["CVE/CWE IDs"]) if merged_data["CVE/CWE IDs"] else "N/A",
"Severity": merged_data["Severity"],
"Recommendation": merged_data["Recommendation"],
"Reference": ', '.join(merged_data["Reference"].split(', ')) if merged_data["Reference"] else "N/A",
"Description": merged_data["Description"]
})
return result
def generate_html_report(vulnerabilities, output_file_path):
severity_color = {
"Critical": {"order": 1, "color": "#C00000"},
"High": {"order": 2, "color": "#FF0000"},
"Medium": {"order": 3, "color": "#ED7D31"},
"Low": {"order": 4, "color": "#70AD47"}
}
html_content = """
<html>
<head>
<title>Nessus Scan Report</title>
<style>
body {
font-family: Verdana, Geneva, sans-serif;
font-size: 10pt;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: left;
}
th {
background-color: #1F497D;
color: white;
text-align: center; /* Center align table headers */
}
.center {
text-align: center; /* Center align specific columns */
vertical-align: middle;
}
.severity-critical {
font-weight: bold;
color: #C00000; /* Red color for Critical */
}
.severity-high {
font-weight: bold;
color: #FF0000; /* Red color for High */
}
.severity-medium {
font-weight: bold;
color: #ED7D31; /* Orange color for Medium */
}
.severity-low {
font-weight: bold;
color: #70AD47; /* Green color for Low */
}
.bold {
font-weight: bold;
color: black; /* Black color for vulnerability name */
}
</style>
</head>
<body>
<table>
<tr>
<th>S.No.</th>
<th class="center">Affected Asset i.e. IP/URL/Application etc.</th>
<th>Observation / Vulnerability Title</th>
<th class="center">CVE-ID / CWE-ID</th>
<th>Severity</th>
<th>Recommendation</th>
<th>Reference</th>
<th>New or Repeated Observation</th>
</tr>
"""
for i, vuln in enumerate(vulnerabilities, start=1):
# Determine the severity class
severity_class = f"severity-{vuln['Severity'].lower()}"
# Build HTML row with bold and centered severity and bold vulnerability name
html_content += f"""
<tr>
<td class="bold">{i}</td>
<td class="center">{vuln['IP(Port)']}</td>
<td><span class="bold">{vuln['Vulnerability Name']}</span></td>
<td class="center">{vuln['CVE/CWE IDs']}</td>
<td class="center"><span class="{severity_class}">{vuln['Severity']}</span></td>
<td>{vuln['Recommendation']}</td>
<td>{', '.join(vuln['Reference'].split())}</td>
<td class="center">New</td>
</tr>
"""
html_content += """
</table>
</body>
</html>
"""
with open(output_file_path, 'w') as file:
file.write(html_content)
def generate_detailed_findings(vulnerabilities, output_file_path):
html_content = """
<html>
<head>
<title>Detailed Findings</title>
<style>
body {
font-family: Verdana, Geneva, sans-serif;
font-size: 10pt;
line-height: 1.5;
}
.bold {
font-weight: bold;
}
.separator {
padding: 10px 0;
}
.indented {
margin-left: 20px; /* Indent by 20px */
display: block; /* Ensures that the indentation applies */
}
</style>
</head>
<body>
"""
for index, vuln in enumerate(vulnerabilities, start=1):
# Combine the references with a comma and space
references = ', '.join(vuln['Reference'].split())
html_content += f"""
<div>
<p><span class="bold">Observation {index}:</span></p>
<p><span class="bold">i. Observation / Vulnerability Title:</span><br>
<span class="indented">{vuln['Vulnerability Name']}</span></p>
<p><span class="bold">ii. Affected Asset i.e. IP/URL/Application etc.:</span><br>
<span class="indented">{vuln['IP(Port)']}</span></p>
<p><span class="bold">iii. Detailed Observation:</span><br>
<span class="indented">{vuln['Description']}</span></p>
<p><span class="indented"><em>Note:</em> This plugin requires ICMP traffic to be unblocked between the scanner and the host.</span></p>
<p><span class="bold">iv. CVE/CWE ID:</span><br>
<span class="indented">{vuln['CVE/CWE IDs']}</span></p>
<p><span class="bold">v. Severity:</span><br>
<span class="indented">{vuln['Severity']}</span></p>
<p><span class="bold">vi. Recommendation:</span><br>
<span class="indented">{vuln['Recommendation']}</span></p>
<p><span class="bold">vii. Reference:</span><br>
<span class="indented">{references}</span></p>
<p><span class="bold">viii. New or Repeat observation:</span><br>
<span class="indented">New</span></p>
<p><span class="bold">ix. Proof of Concept:</span><br>
<span class="indented">Step I: Go to the URL: [Screenshot]</span></p>
</div>
"""
# Add separator between findings
html_content += """
<div class="separator">+++++++++++++++++++++++++++++++++++++++++++++++++++++++++</div>
"""
html_content += """
</body>
</html>
"""
with open(output_file_path, 'w') as file:
file.write(html_content)
if __name__ == "__main__":
print("\n********************************************")
print("* *")
print("* One Peice NESSUS PARSER *")
print("* *")
print("********************************************\n")
nessus_file_path = input("Enter the location of the Nessus file: ")
if nessus_file_path and os.path.exists(nessus_file_path):
parsed_vulnerabilities = parse_nessus_file(nessus_file_path)
nessus_file_name = os.path.basename(nessus_file_path)
nessus_file_name_without_extension = os.path.splitext(nessus_file_name)[0]
# Generate HTML report
output_html_file_path = os.path.join(os.path.dirname(nessus_file_path), f"va_table_{nessus_file_name_without_extension}.html")
generate_html_report(parsed_vulnerabilities, output_html_file_path)
print(f"HTML report generated: {output_html_file_path}")
# Generate detailed findings report as HTML
output_detailed_file_path = os.path.join(os.path.dirname(nessus_file_path), f"detail_finding_{nessus_file_name_without_extension}.html")
generate_detailed_findings(parsed_vulnerabilities, output_detailed_file_path)
print(f"Detailed findings generated: {output_detailed_file_path}")
else:
print("\nA R A - A R A\nCheck the Nessus file path and try again.\n")
#-----------------------------------------------------------------------------------------------------------------------------------------
## POWER ISN'T DETERMINED BY YOUR SIZE
##BUT BY THE SIZE OF YOUR HEART & DREAMS
# FUTURE PIRATE KING " MONKEY D. LUFFY "
#-----------------------------------
# CREATED BY :: PUSHKAR SINGH