mirror of https://github.com/OWASP/Nettacker.git
Made changes following suggestion
1. Change the date format from d/m/Y to Y-m-d (e.g. 2004-08-28) 2. In the return/output of ssl_certificate_scan in SSL library please add certificate "subject" and "issuer" so these could be logged 3. Rename ssl_version module to ssl_weak_version 4. Change ssl_expired_certificate module to return expired certs only ( do not count expiring_soon certs - it is not a vulnerability!) 5. Create a separate ssl_expiring_certificate module in modules/scan (remember 'expiring soon' is not a vulnerability, so we need to make this a 'scan' module) 6. Rename ssl_signed_certificate module to ssl_certificate_weak_signature and remove the self-signed check from it 7. Create a separate ssl_self_signed_certificate module in modules/vuln Next in nettacker/core/lib/ssl.py in class SslLibrary(BaseLibrary): you have ssl_certificate_scan and ssl_version_and_cipher_scan methods. There is a common code in these two methods so these could be refactored to remove the repetition. Please refactor/improve this. In ssl_version_and_cipher_scan also please add add to the output /return certificate "subject" ,"issuer" and an expiry date. This way if a user scans they network using IP addresses and some servers will come up with weak SSL versions/ciphers it will be easier for user to identify the servers using the certificate subject/issuer
This commit is contained in:
parent
5518b140f6
commit
e47ef52929
|
|
@ -18,14 +18,19 @@ def is_weak_hash_algo(algo):
|
|||
return False
|
||||
|
||||
|
||||
def is_weak_ssl_version(host, port, timeout):
|
||||
def test_ssl_version(host, port, timeout, ssl_version=None):
|
||||
try:
|
||||
context = ssl.SSLContext(ssl_version)
|
||||
def create_socket_connection(context, host, port, timeout):
|
||||
socket_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
socket_connection.settimeout(timeout)
|
||||
socket_connection.connect((host, port))
|
||||
socket_connection = context.wrap_socket(socket_connection, server_hostname=host)
|
||||
return socket_connection
|
||||
|
||||
|
||||
def is_weak_ssl_version(host, port, timeout):
|
||||
def test_ssl_version(host, port, timeout, ssl_version=None):
|
||||
try:
|
||||
context = ssl.SSLContext(ssl_version)
|
||||
socket_connection = create_socket_connection(context, host, port, timeout)
|
||||
return socket_connection.version()
|
||||
|
||||
except ssl.SSLError:
|
||||
|
|
@ -43,7 +48,7 @@ def is_weak_ssl_version(host, port, timeout):
|
|||
supported_versions = []
|
||||
lowest_version = ""
|
||||
for ssl_version in ssl_versions:
|
||||
version = test_ssl_verison(host, port, timeout, ssl_version=ssl_version)
|
||||
version = test_ssl_version(host, port, timeout, ssl_version=ssl_version)
|
||||
if version:
|
||||
lowest_version = version
|
||||
supported_versions.append(version)
|
||||
|
|
@ -58,11 +63,7 @@ def is_weak_cipher_suite(host, port, timeout):
|
|||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
context.set_ciphers(cipher)
|
||||
|
||||
socket_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
socket_connection.settimeout(timeout)
|
||||
socket_connection.connect((host, port))
|
||||
socket_connection = context.wrap_socket(socket_connection, server_hostname=host)
|
||||
create_socket_connection(context, host, port, timeout)
|
||||
return True
|
||||
|
||||
except ssl.SSLError:
|
||||
|
|
@ -126,6 +127,25 @@ def create_tcp_socket(host, port, timeout):
|
|||
return socket_connection, ssl_flag
|
||||
|
||||
|
||||
def get_cert_info(cert):
|
||||
x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
|
||||
weak_signing_algo = is_weak_hash_algo(str(x509.get_signature_algorithm()))
|
||||
cert_activation = datetime.strptime(x509.get_notBefore().decode("utf-8"), "%Y%m%d%H%M%S%z")
|
||||
cert_expires = datetime.strptime(x509.get_notAfter().decode("utf-8"), "%Y%m%d%H%M%S%z")
|
||||
return {
|
||||
"expired": x509.has_expired(),
|
||||
"self_signed": x509.get_issuer() == x509.get_subject(),
|
||||
"issuer": str(x509.get_issuer()),
|
||||
"subject": str(x509.get_subject()),
|
||||
"signing_algo": str(x509.get_signature_algorithm()),
|
||||
"weak_signing_algo": weak_signing_algo,
|
||||
"activation_date": cert_activation.strftime("%Y/%m/%d"),
|
||||
"not_activated": (cert_activation - datetime.now(timezone.utc)).days > 0,
|
||||
"expiration_date": cert_expires.strftime("%Y/%m/%d"),
|
||||
"expiring_soon": (cert_expires - datetime.now(timezone.utc)).days < 30,
|
||||
}
|
||||
|
||||
|
||||
class SslLibrary(BaseLibrary):
|
||||
def ssl_certificate_scan(self, host, port, timeout):
|
||||
tcp_socket = create_tcp_socket(host, port, timeout)
|
||||
|
|
@ -134,33 +154,19 @@ class SslLibrary(BaseLibrary):
|
|||
|
||||
socket_connection, ssl_flag = tcp_socket
|
||||
peer_name = socket_connection.getpeername()
|
||||
scan_info = {
|
||||
"ssl_flag": ssl_flag,
|
||||
"peer_name": peer_name,
|
||||
"service": socket.getservbyport(int(port)),
|
||||
}
|
||||
|
||||
if ssl_flag:
|
||||
cert = ssl.get_server_certificate((host, port))
|
||||
x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
|
||||
weak_signing_algo = is_weak_hash_algo(str(x509.get_signature_algorithm()))
|
||||
cert_activation = datetime.strptime(
|
||||
x509.get_notBefore().decode("utf-8"), "%Y%m%d%H%M%S%z"
|
||||
)
|
||||
cert_expires = datetime.strptime(x509.get_notAfter().decode("utf-8"), "%Y%m%d%H%M%S%z")
|
||||
cert_info = get_cert_info(cert)
|
||||
scan_info = cert_info | scan_info
|
||||
return scan_info
|
||||
|
||||
return {
|
||||
"expired": x509.has_expired(),
|
||||
"self_signed": x509.get_issuer() == x509.get_subject(),
|
||||
"signing_algo": str(x509.get_signature_algorithm()),
|
||||
"weak_signing_algo": weak_signing_algo,
|
||||
"activation_date": cert_activation.strftime("%d/%m/%Y"),
|
||||
"not_activated": (cert_activation - datetime.now(timezone.utc)).days > 0,
|
||||
"expiration_date": cert_expires.strftime("%d/%m/%Y"),
|
||||
"expiring_soon": (cert_expires - datetime.now(timezone.utc)).days < 30,
|
||||
"ssl_flag": ssl_flag,
|
||||
"peer_name": peer_name,
|
||||
"service": socket.getservbyport(int(port)),
|
||||
}
|
||||
return {
|
||||
"ssl_flag": ssl_flag,
|
||||
"peer_name": peer_name,
|
||||
"service": socket.getservbyport(int(port)),
|
||||
}
|
||||
return scan_info
|
||||
|
||||
def ssl_version_and_cipher_scan(self, host, port, timeout):
|
||||
tcp_socket = create_tcp_socket(host, port, timeout)
|
||||
|
|
@ -171,6 +177,11 @@ class SslLibrary(BaseLibrary):
|
|||
peer_name = socket_connection.getpeername()
|
||||
|
||||
if ssl_flag:
|
||||
try:
|
||||
cert = ssl.get_server_certificate((host, port))
|
||||
except ssl.SSLError:
|
||||
cert = None
|
||||
cert_info = get_cert_info(cert) if cert else None
|
||||
ssl_ver, weak_version = is_weak_ssl_version(host, port, timeout)
|
||||
cipher_suite, weak_cipher_suite = is_weak_cipher_suite(host, port, timeout)
|
||||
|
||||
|
|
@ -179,6 +190,9 @@ class SslLibrary(BaseLibrary):
|
|||
"weak_version": weak_version,
|
||||
"cipher_suite": cipher_suite,
|
||||
"weak_cipher_suite": weak_cipher_suite,
|
||||
"issuer": cert_info["issuer"] if cert_info else "NA",
|
||||
"subject": cert_info["subject"] if cert_info else "NA",
|
||||
"expiration_date": cert_info["expiration_date"] if cert_info else "NA",
|
||||
"ssl_flag": ssl_flag,
|
||||
"peer_name": peer_name,
|
||||
"service": socket.getservbyport(int(port)),
|
||||
|
|
|
|||
|
|
@ -49,10 +49,12 @@ class Module:
|
|||
"subdomain_scan",
|
||||
"icmp_scan",
|
||||
"port_scan",
|
||||
"ssl_version_vuln",
|
||||
"ssl_weak_version_vuln",
|
||||
"ssl_weak_cipher_vuln",
|
||||
"ssl_signed_certificate_vuln",
|
||||
"ssl_certificate_weak_signature_vuln",
|
||||
"ssl_self_signed_certificate_vuln",
|
||||
"ssl_expired_certificate_vuln",
|
||||
"ssl_expiring_certificate_scan",
|
||||
]
|
||||
|
||||
contents = TemplateLoader("port_scan", {"target": ""}).load()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
info:
|
||||
name: ssl_expiring_certificate_scan
|
||||
author: Captain-T2004
|
||||
severity: 6
|
||||
description: check if the ssl certificate is expiring soon
|
||||
reference:
|
||||
- https://www.beyondsecurity.com/resources/vulnerabilities/ssl-certificate-expiry
|
||||
profiles:
|
||||
- scan
|
||||
- ssl
|
||||
|
||||
payloads:
|
||||
- library: ssl
|
||||
steps:
|
||||
- method: ssl_certificate_scan
|
||||
timeout: 3
|
||||
host: "{target}"
|
||||
ports:
|
||||
- 21
|
||||
- 25
|
||||
- 110
|
||||
- 143
|
||||
- 443
|
||||
- 587
|
||||
- 990
|
||||
- 1080
|
||||
- 8080
|
||||
response:
|
||||
condition_type: or
|
||||
conditions:
|
||||
grouped_conditions:
|
||||
condition_type: and
|
||||
conditions:
|
||||
expiring_soon:
|
||||
reverse: false
|
||||
expiration_date:
|
||||
reverse: false
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
info:
|
||||
name: ssl_certificate_vuln
|
||||
name: ssl_certificate_weak_signature_vuln
|
||||
author: Captain-T2004
|
||||
severity: 6
|
||||
description: check if there are any ssl_certificate vulnerabilities present
|
||||
|
|
@ -28,8 +28,6 @@ payloads:
|
|||
response:
|
||||
condition_type: or
|
||||
conditions:
|
||||
self_signed:
|
||||
reverse: false
|
||||
grouped_conditions:
|
||||
condition_type: and
|
||||
conditions:
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
info:
|
||||
name: ssl_certificate_vuln
|
||||
name: ssl_expired_certificate_vuln
|
||||
author: Captain-T2004
|
||||
severity: 6
|
||||
description: check if there are any ssl_certificate vulnerabilities present
|
||||
|
|
@ -36,13 +36,6 @@ payloads:
|
|||
expiration_date:
|
||||
reverse: false
|
||||
grouped_conditions_2:
|
||||
condition_type: and
|
||||
conditions:
|
||||
expiring_soon:
|
||||
reverse: false
|
||||
expiration_date:
|
||||
reverse: false
|
||||
grouped_conditions_3:
|
||||
condition_type: and
|
||||
conditions:
|
||||
not_activated:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
info:
|
||||
name: ssl_self_signed_certificate_vuln
|
||||
author: Captain-T2004
|
||||
severity: 6
|
||||
description: check if the ssl certificate is self-signed
|
||||
reference:
|
||||
- https://www.ssl.com/article/ssl-tls-self-signed-certificates/
|
||||
profiles:
|
||||
- scan
|
||||
- ssl
|
||||
|
||||
payloads:
|
||||
- library: ssl
|
||||
steps:
|
||||
- method: ssl_certificate_scan
|
||||
timeout: 3
|
||||
host: "{target}"
|
||||
ports:
|
||||
- 21
|
||||
- 25
|
||||
- 110
|
||||
- 143
|
||||
- 443
|
||||
- 587
|
||||
- 990
|
||||
- 1080
|
||||
- 8080
|
||||
response:
|
||||
condition_type: or
|
||||
conditions:
|
||||
grouped_conditions:
|
||||
condition_type: and
|
||||
conditions:
|
||||
self_signed:
|
||||
reverse: false
|
||||
issuer:
|
||||
reverse: false
|
||||
subject:
|
||||
reverse: false
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
info:
|
||||
name: ssl_version_vuln
|
||||
name: ssl_weak_cipher_vuln
|
||||
author: Captain-T2004
|
||||
severity: 6
|
||||
description: check if ssl version is unsafe or uses any bad ciphers.
|
||||
|
|
@ -36,4 +36,3 @@ payloads:
|
|||
reverse: false
|
||||
cipher_suite:
|
||||
reverse: false
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
info:
|
||||
name: ssl_version_vuln
|
||||
name: ssl_weak_version_vuln
|
||||
author: Captain-T2004
|
||||
severity: 6
|
||||
description: check if ssl version is unsafe or uses any bad ciphers.
|
||||
|
|
@ -36,3 +36,9 @@ payloads:
|
|||
reverse: false
|
||||
ssl_version:
|
||||
reverse: false
|
||||
issuer:
|
||||
reverse: false
|
||||
subject:
|
||||
reverse: false
|
||||
expiration_date:
|
||||
reverse: false
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
from unittest.mock import patch
|
||||
|
||||
from nettacker.core.lib.socket import create_tcp_socket, SocketEngine
|
||||
from tests.common import TestCase
|
||||
|
||||
|
|
|
|||
|
|
@ -53,27 +53,30 @@ class Mockx509Object:
|
|||
|
||||
|
||||
class Responses:
|
||||
ssl_version_vuln = {
|
||||
ssl_weak_version_vuln = {
|
||||
"ssl_version": ["TLSv1"],
|
||||
"weak_version": True,
|
||||
"ssl_flag": True,
|
||||
"issuer": "test_issuer",
|
||||
"subject": "test_subject",
|
||||
"expiration_date": "2100/12/07",
|
||||
}
|
||||
|
||||
ssl_certificate_expired = {
|
||||
"expired": True,
|
||||
"expiration_date": "07/12/2023",
|
||||
"expiration_date": "2023/12/07",
|
||||
"not_activated": False,
|
||||
"activation_date": "07/12/2023",
|
||||
"activation_date": "2023/12/07",
|
||||
"expiring_soon": True,
|
||||
"ssl_flag": True,
|
||||
}
|
||||
|
||||
ssl_certificate_deactivated = {
|
||||
"expired": False,
|
||||
"expiration_date": "07/12/2100",
|
||||
"expiration_date": "2100/12/07",
|
||||
"expiring_soon": False,
|
||||
"not_activated": True,
|
||||
"activation_date": "07/12/2100",
|
||||
"activation_date": "2100/12/07",
|
||||
"ssl_flag": True,
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +84,7 @@ class Responses:
|
|||
|
||||
|
||||
class Substeps:
|
||||
ssl_version_vuln = {
|
||||
ssl_weak_version_vuln = {
|
||||
"method": "ssl_version_and_cipher_scan",
|
||||
"response": {
|
||||
"condition_type": "or",
|
||||
|
|
@ -91,6 +94,9 @@ class Substeps:
|
|||
"conditions": {
|
||||
"weak_version": {"reverse": False},
|
||||
"ssl_version": {"reverse": False},
|
||||
"issuer": {"reverse": False},
|
||||
"subject": {"reverse": False},
|
||||
"expiration_date": {"reverse": False},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
|
@ -110,13 +116,6 @@ class Substeps:
|
|||
},
|
||||
},
|
||||
"grouped_conditions_2": {
|
||||
"condition_type": "and",
|
||||
"conditions": {
|
||||
"expiring_soon": {"reverse": False},
|
||||
"expiration_date": {"reverse": False},
|
||||
},
|
||||
},
|
||||
"grouped_conditions_3": {
|
||||
"condition_type": "and",
|
||||
"conditions": {
|
||||
"not_activated": {"reverse": False},
|
||||
|
|
@ -164,6 +163,9 @@ class TestSocketMethod(TestCase):
|
|||
"peer_name": "example.com",
|
||||
"cipher_suite": ["HIGH"],
|
||||
"weak_cipher_suite": False,
|
||||
"issuer": "NA",
|
||||
"subject": "NA",
|
||||
"expiration_date": "NA",
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -180,6 +182,9 @@ class TestSocketMethod(TestCase):
|
|||
"peer_name": "example.com",
|
||||
"cipher_suite": ["LOW"],
|
||||
"weak_cipher_suite": True,
|
||||
"issuer": "NA",
|
||||
"subject": "NA",
|
||||
"expiration_date": "NA",
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -223,10 +228,12 @@ class TestSocketMethod(TestCase):
|
|||
"ssl_flag": True,
|
||||
"service": "http",
|
||||
"self_signed": False,
|
||||
"issuer": "test_issuer",
|
||||
"subject": "test_subject",
|
||||
"expiring_soon": False,
|
||||
"expiration_date": "07/12/2100",
|
||||
"expiration_date": "2100/12/07",
|
||||
"not_activated": False,
|
||||
"activation_date": "07/12/2023",
|
||||
"activation_date": "2023/12/07",
|
||||
"signing_algo": "test_algo",
|
||||
"weak_signing_algo": False,
|
||||
"peer_name": "example.com",
|
||||
|
|
@ -250,10 +257,12 @@ class TestSocketMethod(TestCase):
|
|||
"ssl_flag": True,
|
||||
"service": "http",
|
||||
"self_signed": True,
|
||||
"issuer": "test_issuer_subject",
|
||||
"subject": "test_issuer_subject",
|
||||
"expiring_soon": False,
|
||||
"expiration_date": "07/12/2100",
|
||||
"expiration_date": "2100/12/07",
|
||||
"not_activated": True,
|
||||
"activation_date": "07/12/2100",
|
||||
"activation_date": "2100/12/07",
|
||||
"signing_algo": "test_algo",
|
||||
"weak_signing_algo": True,
|
||||
"peer_name": "example.com",
|
||||
|
|
@ -358,7 +367,7 @@ class TestSocketMethod(TestCase):
|
|||
engine.response_conditions_matched(
|
||||
Substep.ssl_expired_certificate_scan, Response.ssl_certificate_expired
|
||||
),
|
||||
{"expired": True, "expiration_date": "07/12/2023", "expiring_soon": True},
|
||||
{"expired": True, "expiration_date": "2023/12/07"},
|
||||
)
|
||||
# ssl_certificate_scan_not_activated
|
||||
self.assertEqual(
|
||||
|
|
@ -366,21 +375,29 @@ class TestSocketMethod(TestCase):
|
|||
Substep.ssl_expired_certificate_scan,
|
||||
Response.ssl_certificate_deactivated,
|
||||
),
|
||||
{"not_activated": True, "activation_date": "07/12/2100"},
|
||||
{"not_activated": True, "activation_date": "2100/12/07"},
|
||||
)
|
||||
|
||||
# ssl_version_vuln
|
||||
# ssl_weak_version_vuln
|
||||
self.assertEqual(
|
||||
engine.response_conditions_matched(
|
||||
Substep.ssl_version_vuln, Response.ssl_version_vuln
|
||||
Substep.ssl_weak_version_vuln, Response.ssl_weak_version_vuln
|
||||
),
|
||||
{"weak_version": True, "ssl_version": ["TLSv1"]},
|
||||
{
|
||||
"weak_version": True,
|
||||
"ssl_version": ["TLSv1"],
|
||||
"issuer": "test_issuer",
|
||||
"subject": "test_subject",
|
||||
"expiration_date": "2100/12/07",
|
||||
},
|
||||
)
|
||||
|
||||
# ssl_* scans with ssl_flag = False
|
||||
self.assertEqual(
|
||||
engine.response_conditions_matched(Substep.ssl_version_vuln, Response.ssl_off), []
|
||||
engine.response_conditions_matched(Substep.ssl_weak_version_vuln, Response.ssl_off), []
|
||||
)
|
||||
|
||||
# * scans with response None i.e. TCP connection failed(None)
|
||||
self.assertEqual(engine.response_conditions_matched(Substep.ssl_version_vuln, None), [])
|
||||
self.assertEqual(
|
||||
engine.response_conditions_matched(Substep.ssl_weak_version_vuln, None), []
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue