-
Notifications
You must be signed in to change notification settings - Fork 2
/
cve-scanner-debian.py
143 lines (111 loc) · 6.31 KB
/
cve-scanner-debian.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
import argparse
import subprocess
import requests
import json
from bs4 import BeautifulSoup
# Function to get a list of all installed packages and their versions
def get_installed_packages():
package_list = []
try:
# Use dpkg-query to list all installed packages and their versions
dpkg_query = subprocess.Popen(["dpkg-query", "-W"], stdout=subprocess.PIPE, text=True)
dpkg_output = dpkg_query.communicate()[0]
for line in dpkg_output.split('\n'):
parts = line.split()
if len(parts) >= 2:
package = parts[0]
version = parts[1]
package_list.append({"package": package, "version": version})
except Exception as e:
print(f"Error while getting installed packages: {e}")
return package_list
# Function to search for CVEs for a package
def search_cve(package, version):
try:
# Query the NVD database for CVE information
cve_url = f"https://nvd.nist.gov/vuln/search/results?form_type=Basic&results_type=overview&query={package}&search_type=all"
response = requests.get(cve_url)
response.raise_for_status() # Check for HTTP errors
cve_entries = []
for row in BeautifulSoup(response.text, 'html.parser').find_all('tr', {'data-testid': 'vuln-row-0'}):
cve_id = row.find('a', {'data-testid': 'vuln-detail-link-0'})
description = row.find('p', {'data-testid': 'vuln-summary-0'})
severity_span = row.find('span', {'id': 'cvss3-link'})
if cve_id and description and severity_span:
cve_id = cve_id.text.strip()
description = description.text.strip()
severity = severity_span.text.strip().upper() # Convert to uppercase for comparison
# Extract the severity score from the span
severity_score = severity_span.find('a', {'class': 'label'}).text.strip()
cve_entries.append({"CVE": cve_id, "Description": description, "Severity": severity_score})
# Sort CVEs by severity (descending order)
cve_entries.sort(key=lambda x: x['Severity'], reverse=True)
return cve_entries
except Exception as e:
print(f"Error while searching for CVEs: {e}")
return []
def main():
parser = argparse.ArgumentParser(description="Scan all installed packages for CVEs and export results in HTML or JSON format.")
parser.add_argument("--html", action="store_true", help="Export results in HTML format.")
parser.add_argument("--json", action="store_true", help="Export results in JSON format.")
parser.add_argument("-s", "--search", help="Search for CVEs related to a specific package.")
args = parser.parse_args()
if not args.html and not args.json:
print("Please specify either --html or --json to export results.")
return
installed_packages = get_installed_packages()
cve_found = False # Flag to track if CVEs were found
if not installed_packages:
print("No packages found.")
return
results = []
for package_info in installed_packages:
package = package_info["package"]
version = package_info["version"]
# Perform dynamic package search if -s switch is provided
if args.search and args.search.lower() not in package.lower():
continue
print(f"Scanning package: {package} (Version: {version})")
cve_entries = search_cve(package, version)
if cve_entries:
if not cve_found:
print("CVEs found with HIGH and CRITICAL severity (sorted by severity):")
cve_found = True
for cve in cve_entries:
# Check severity and apply appropriate CSS class
severity_class = ""
if "HIGH" in cve['Severity'] or "CRITICAL" in cve['Severity']:
severity_class = "high-severity"
elif "MEDIUM" in cve['Severity']:
severity_class = "medium-severity"
print(f"CVE ID: {cve['CVE']}")
print(f"Description: {cve['Description']}")
print(f"Severity: {cve['Severity']}\n")
results.append({"Package": package, "Version": version, "CVE": cve['CVE'], "Description": cve['Description'], "Severity": cve['Severity'], "SeverityClass": severity_class})
if args.html:
# Generate an HTML table if CVEs were found and save it to an HTML file
if cve_found:
file_name = f"cve_report_{args.search.lower()}.html" if args.search else "cve_report_all.html"
html_table = "<html><head><title>CVEs Found</title><style>table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } th { background-color: #f2f2f2; } tr:nth-child(even) { background-color: #f2f2f2; } .medium-severity { color: darkorange; } .high-severity, .critical-severity { color: red; } </style></head><body>"
html_table += "<h1>CVEs Found</h1>"
html_table += "<table><tr><th>Package</th><th>Version</th><th>CVE ID</th><th>Description</th><th>Severity</th></tr>"
for result in results:
html_table += f"<tr><td>{result['Package']}</td><td>{result['Version']}</td><td>{result['CVE']}</td><td>{result['Description']}</td><td class='{result['SeverityClass']}'>{result['Severity']}</td></tr>"
html_table += "</table></body></html>"
# Save the HTML table to an HTML file
with open(file_name, "w", encoding="utf-8") as html_file:
html_file.write(html_table)
print(f"CVE report saved as '{file_name}'")
else:
print("No CVEs found.")
if args.json:
# Export results in JSON format
if results:
file_name = f"cve_report_{args.search.lower()}.json" if args.search else "cve_report_all.json"
with open(file_name, "w", encoding="utf-8") as json_file:
json.dump(results, json_file, indent=4)
print(f"CVE report saved as '{file_name}'")
else:
print("No CVEs found.")
if __name__ == "__main__":
main()