-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathgenerate-report-testssl.py
122 lines (109 loc) · 5.17 KB
/
generate-report-testssl.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
#!/usr/bin/env python
import json
import os
import colorama
import re
from termcolor import colored
'''
Quick script to format the result of a batch scan of TestSSL:
bash testssl.sh --file commands.txt
python generate-report-testssl.py
Where "commands.txt" contains:
-s -p -U --quiet -oJ host1.json host1:443
-s -p -U --quiet -oJ host2.json host2:443
TestSSL scan results must be in JSON format using the "-oJ" parameter.
The script process all TestSSL JSON reports found in the current execution folder.
Dependencies:
pip install colorama termcolor
'''
INFORMATIONAL_SEVERITY = ["OK", "INFO", "WARN"]
SEVERITY_COLOR_MAPPING = {"CRITICAL": "red", "HIGH": "red", "MEDIUM": "yellow", "LOW": "cyan"}
TESTSSL_SCRIPT_FILE_LOCATION = "/tools/testssl/testssl.sh"
# See the function "run_cipherlists()" in the source code for the mapping values
TESTSSL_SCRIPT_CIPHERSUITE_ID_TO_CODEVARIABLE_MAPPING = {"cipherlist_OBSOLETED": "ossl_obsoleted_ciphers", "cipherlist_NULL": "ossl_null_ciphers",
"cipherlist_aNULL": "ossl_anon_ciphers", "cipherlist_3DES_IDEA": "ossl_tdes_ciphers",
"cipherlist_LOW": "ossl_low_ciphers", "cipherlist_EXPORT": "ossl_exp_ciphers"}
def get_color(severity):
sev = severity.upper()
severity_color = "white"
if sev in SEVERITY_COLOR_MAPPING:
severity_color = SEVERITY_COLOR_MAPPING[sev]
return severity_color
def get_ciphersuite_algorithms_from_testssl_script(ciphersuite_testssl_code):
algo = None
if ciphersuite_testssl_code in TESTSSL_SCRIPT_CIPHERSUITE_ID_TO_CODEVARIABLE_MAPPING:
code = TESTSSL_SCRIPT_CIPHERSUITE_ID_TO_CODEVARIABLE_MAPPING[ciphersuite_testssl_code]
with open(TESTSSL_SCRIPT_FILE_LOCATION, mode="r", encoding="utf-8") as f:
content = f.read()
expr = code + r'\s*=\s*\'(.*?)\''
algs = re.findall(expr, content, re.IGNORECASE)
if len(algs) > 0:
algo = algs[0]
return algo
def process_host(json_file):
findings = []
buffer = []
lines = []
with open(json_file, mode="r", encoding="utf-8") as f:
content = f.read()
if "testssl.sh" in content and "scanResult" in content:
json_data = json.loads(content)
scan_results = json_data["scanResult"]
for scan_result in scan_results:
findings.clear()
buffer.clear()
# Protocols
for protocol in scan_result["protocols"]:
if protocol["severity"].upper() not in INFORMATIONAL_SEVERITY:
severity_color = get_color(protocol["severity"])
id = colored(protocol["id"], severity_color)
desc = protocol["finding"]
findings.append(f"{id:<30} => {desc}")
if len(findings) > 0:
buffer.append("[*] Deprecated protocols identified:")
buffer.append("\n".join(findings))
findings.clear()
# Ciphers
for ciphersuite in scan_result["ciphers"]:
if ciphersuite["severity"].upper() not in INFORMATIONAL_SEVERITY:
severity_color = get_color(ciphersuite["severity"])
id = colored(ciphersuite["id"], severity_color)
desc = ciphersuite["finding"]
algo = get_ciphersuite_algorithms_from_testssl_script(ciphersuite["id"])
if algo is not None:
desc = f"{desc} ({algo})"
findings.append(f"{id:<30} => {desc}")
if len(findings) > 0:
buffer.append("[*] Deprecated cipher suites identified:")
buffer.append("\n".join(findings))
findings.clear()
# CVE
for vulnerability in scan_result["vulnerabilities"]:
if vulnerability["severity"].upper() not in INFORMATIONAL_SEVERITY:
severity_color = get_color(vulnerability["severity"])
id = colored(vulnerability["id"], severity_color)
desc = vulnerability["finding"]
cve = ""
if "cve" in vulnerability:
cve = "(" + vulnerability["cve"] + ")"
if len(desc) > 120:
desc = desc[:120] + "..."
findings.append(f"{id:<30} => {desc} {cve}")
if len(findings) > 0:
buffer.append("[*] Vulnerabilities identified:")
buffer.append("\n".join(findings))
# Summary
if len(buffer) > 0:
host = scan_result["targetHost"] + ":" + scan_result["port"] + " (rDNS: " + scan_result["rDNS"] + ")"
lines.append(colored(f"==== Host {host}", "magenta", attrs=["bold"]))
lines.extend(buffer)
lines.append("")
if len(lines) > 0:
print("\n".join(lines))
colorama.init()
json_files = [f for f in os.listdir() if os.path.isfile(f) and f.endswith(".json")]
if len(json_files) == 0:
print(colored("[!] No TestSSL JSON scan report found in the current folder!", "red"))
else:
for json_file in json_files:
process_host(json_file)