Beispiel #1
0
def has_tls13_downgrade_vuln(site: str, port: int = PORT) -> bool:
    """
    Check if server is prone to TLSv1.3 downgrade attack.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    supported = []
    for version in reversed(range(0, 5)):
        try:
            with connect(site,
                         port=port,
                         min_version=(3, version),
                         max_version=(3, version)):
                supported.append(version)
        except (tlslite.errors.TLSRemoteAlert, tlslite.errors.TLSLocalAlert,
                OSError):
            continue
    if not supported:
        show_unknown('Could not connect to server',
                     details=dict(site=site, port=port))
        return False

    if 4 not in supported:
        show_unknown('Site does not support TLSv1.3',
                     details=dict(site=site, port=port))
        return False
    if len(supported) > 1:
        try:
            with connect(site,
                         port=port,
                         min_version=(3, min(supported)),
                         max_version=(3, min(supported)),
                         key_exchange_names=['rsa']):
                show_open('Site supports TLSv1.3 and older versions and \
supports RSA keys without (EC)DH(E) cipher suites',
                          details=dict(site=site,
                                       port=port,
                                       supported=supported))
                result = True
        except (tlslite.errors.TLSRemoteAlert,
                tlslite.errors.TLSAbruptCloseError):
            show_close('Site supports TLSv1.3 older versions but \
RSA keys require (EC)DH(E) cipher suites',
                       details=dict(site=site, port=port, supported=supported))
            result = False
        except (tlslite.errors.TLSLocalAlert, socket.error) as exc:
            show_unknown('Could not connect',
                         details=dict(site=site, port=port, error=str(exc)))
            result = False
    else:
        show_close('Site not vulnerable to TLSv1.3 downgrade attack',
                   details=dict(site=site, port=port, supported=supported))
        result = False
    return result
Beispiel #2
0
def allows_insecure_downgrade(site: str, port: int = PORT) -> bool:
    """
    Check if site has support for TLS_FALLBACK_SCSV extension.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    supported = []
    for version in reversed(range(0, 5)):
        try:
            with connect(site, port=port, max_version=(3, version)):
                supported.append(version)
        except (tlslite.errors.TLSRemoteAlert, OSError):
            continue
        except tlslite.errors.TLSLocalAlert:
            show_unknown('Port does not support SSL/TLS',
                         details=dict(site=site, port=port))
            return False
    if not supported:
        show_unknown('Could not connect to server',
                     details=dict(site=site, port=port))
        return False

    result = True

    if len(supported) > 1 and any(x in (0, 1, 2) for x in supported):
        try:
            with connect(site,
                         port=port,
                         max_version=(3, min(supported)),
                         scsv=True):
                show_open('Site does not support TLS_FALLBACK_SCSV',
                          details=dict(site=site, port=port))
                result = True
        except tlslite.errors.TLSRemoteAlert as exc:
            if str(exc) in ('inappropriate_fallback', 'close_notify'):
                show_close('Site supports TLS_FALLBACK_SCSV',
                           details=dict(site=site, port=port))
            else:
                show_unknown('Could not connect to server',
                             details=dict(site=site,
                                          port=port,
                                          error=str(exc).replace(':', ',')))
            result = False
    else:
        show_close('Host does not support multiple TLS versions',
                   details=dict(site=site, port=port))
        result = False
    return result
Beispiel #3
0
def has_sweet32(site: str, port: int = PORT) -> bool:
    """
    Check if server is vulnerable to SWEET32.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    result = False
    try:
        with connect(site,
                     port=port,
                     cipher_names=["3des"],
                     min_version=(3, 1),
                     max_version=(3, 3)):
            show_open('Site vulnerable to SWEET32',
                      details=dict(site=site, port=port))
            result = True
    except (tlslite.errors.TLSRemoteAlert, tlslite.errors.TLSAbruptCloseError,
            socket.error):
        result = False
        show_close('Site not vulnerable to SWEET32',
                   details=dict(site=site, port=port))
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        result = False
    return result
Beispiel #4
0
def tls_uses_cbc(site: str, port: int = PORT) -> bool:
    """
    Check if TLS connection uses CBC.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    result = False
    try:
        with connect(site, port=port, min_version=(3, 1),
                     max_version=(3, 3)) as conn:
            if conn._recordLayer.isCBCMode():  # noqa
                show_open('Site uses TLS CBC ciphers and may be vulnerable to \
to GOLDENDOODLE and Zombie POODLE attacks',
                          details=dict(site=site, port=port))
                result = True
            else:
                show_close('Site does not use TLS CBC ciphers',
                           details=dict(site=site, port=port))
                result = False
    except (tlslite.errors.TLSRemoteAlert, tlslite.errors.TLSAbruptCloseError,
            socket.error) as exc:
        result = False
        show_unknown('Could not connect',
                     details=dict(site=site, port=port, error=str(exc)))
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        result = False
    return result
Beispiel #5
0
def not_tls13_enabled(site: str, port: int = PORT) -> bool:
    """
    Check if site has TLSv1.3 enabled.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    result = True
    try:
        with connect(site, port=port, min_version=(3, 4), max_version=(3, 4)):
            show_close('Site supports TLSv1.3',
                       details=dict(site=site, port=port))
            result = False
    except (tlslite.errors.TLSLocalAlert) as exc:
        if exc.message and 'Too old version' in exc.message:
            show_open('Site does not support TLSv1.3',
                      details=dict(site=site, port=port))
            return True
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        return False
    except socket.error as exc:
        result = False
        show_unknown('Could not connect',
                     details=dict(site=site, port=port, error=str(exc)))
    return result
Beispiel #6
0
def allows_weak_ciphers(site: str, port: int = PORT) -> bool:
    """
    Check if site accepts weak cipher suites.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    result = True
    try:
        with connect(site, port=port, cipher_names=['rc4', '3des', 'null']):
            show_open('Site allows weak (RC4, 3DES and NULL) cipher \
suites',
                      details=dict(site=site, port=port))
            result = True
    except (tlslite.errors.TLSRemoteAlert, tlslite.errors.TLSAbruptCloseError):
        show_close('Site not allows weak (RC4, 3DES and NULL) cipher \
suites',
                   details=dict(site=site, port=port))
        result = False
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        result = False
    except socket.error as exc:
        result = False
        show_unknown('Could not connect',
                     details=dict(site=site, port=port, error=str(exc)))
    return result
Beispiel #7
0
def has_beast(site: str, port: int = PORT) -> bool:
    """
    Check if site allows BEAST attack.

    See our `blog entry on BEAST
    <https://fluidattacks.com/web/blog/release-the-beast/>`_.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    result = True
    try:
        with connect(site, port=port, min_version=(3, 1),
                     max_version=(3, 1)) as conn:
            if conn._recordLayer.isCBCMode():  # noqa
                show_open('Site enables BEAST attack to clients',
                          details=dict(site=site, port=port))
                result = True
    except (tlslite.errors.TLSRemoteAlert, tlslite.errors.TLSAbruptCloseError):
        show_close('Site not enables BEAST attack to clients',
                   details=dict(site=site, port=port))
        result = False
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        result = False
    except socket.error as exc:
        show_unknown('Could not connect',
                     details=dict(site=site, port=port, error=str(exc)))
        result = False
    return result
Beispiel #8
0
def has_poodle_sslv3(site: str, port: int = PORT) -> bool:
    """
    Check if POODLE SSLv3 is present.

    See our `blog entry on POODLE
    <https://fluidattacks.com/web/blog/treacherous-poodle/>`_.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    result = False
    try:
        with connect(site,
                     port=port,
                     min_version=(3, 0),
                     cipher_names=["aes256", "aes128", "3des"],
                     max_version=(3, 0),
                     check='POODLE'):
            show_open('Site vulnerable to POODLE SSLv3 attack',
                      details=dict(site=site, port=port))
            return True
    except (tlslite.errors.TLSRemoteAlert, tlslite.errors.TLSAbruptCloseError):
        show_close('Site not vulnerable to POODLE SSLv3 attack',
                   details=dict(site=site, port=port))
        result = False
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        result = False
    except socket.error as exc:
        result = False
        show_unknown('Could not connect',
                     details=dict(site=site, port=port, error=str(exc)))
    return result
Beispiel #9
0
def allows_anon_ciphers(site: str, port: int = PORT) -> bool:
    """
    Check if site accepts anonymous cipher suites.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    result = True
    try:
        with connect(site, port=port, anon=True):
            show_open('Site allows anonymous cipher suites',
                      details=dict(site=site, port=port))
            result = True
    except (tlslite.errors.TLSRemoteAlert, tlslite.errors.TLSAbruptCloseError):
        show_close('Site not allows anonymous cipher suites',
                   details=dict(site=site, port=port))
        result = False
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        result = False
    except socket.error as exc:
        result = False
        show_unknown('Could not connect',
                     details=dict(site=site, port=port, error=str(exc)))
    return result
Beispiel #10
0
def is_pfs_disabled(site: str, port: int = PORT) -> bool:
    """
    Check if PFS is enabled.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    try:
        with connect(site,
                     port=port,
                     key_exchange_names=[
                         'dhe_rsa', 'ecdhe_rsa', 'ecdh_anon', 'dh_anon'
                     ]):
            show_close('Forward Secrecy enabled on site',
                       details=dict(site=site, port=port))
            result = False
    except (tlslite.errors.TLSRemoteAlert, tlslite.errors.TLSAbruptCloseError):
        show_open('Forward Secrecy not enabled on site',
                  details=dict(site=site, port=port))
        return True
    except (tlslite.errors.TLSLocalAlert, socket.error) as exc:
        show_unknown('Could not connect',
                     details=dict(site=site, port=port, error=str(exc)))
        result = False
    return result
Beispiel #11
0
def is_tlsv11_enabled(site: str, port: int = PORT) -> bool:
    """
    Check if TLSv1.1 suites are enabled.

    :param site: Address to connect to.
    :param port: If necessary, specify port to connect to.
    """
    result = True
    try:
        with connect(site, port=port, min_version=(3, 2), max_version=(3, 2)):
            show_open('TLSv1.1 enabled on site',
                      details=dict(site=site, port=port))
            result = True
    except (tlslite.errors.TLSRemoteAlert, tlslite.errors.TLSAbruptCloseError):
        show_close('TLSv1.1 not enabled on site',
                   details=dict(site=site, port=port))
        result = False
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        result = False
    except socket.error as exc:
        result = False
        show_unknown('Could not connect',
                     details=dict(site=site, port=port, error=str(exc)))
    return result
Beispiel #12
0
def is_cert_validity_lifespan_unsafe(site: str, port: int = PORT) -> bool:
    """
    Check if certificate lifespan is larger than two years which is insecure.

    :param site: Site address.
    :param port: Port to connect to.
    """
    max_validity_days = 730

    result = True
    try:
        with connect(site, port=port) as conn:
            __cert = conn.session.serverCertChain.x509List[0].bytes
            cert = ssl.DER_cert_to_PEM_cert(__cert)
    except socket.error:
        show_unknown('Port closed', details=dict(site=site, port=port))
        return False
    except tlslite.errors.TLSRemoteAlert as exc:
        show_unknown('Could not connect',
                     details=dict(site=site,
                                  port=port,
                                  error=str(exc).replace(':', ',')))
        return False
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        return False
    cert_obj = load_pem_x509_certificate(cert.encode('utf-8'),
                                         default_backend())

    cert_validity = \
        cert_obj.not_valid_after - cert_obj.not_valid_before

    if cert_validity.days <= max_validity_days:
        show_close('Certificate has a secure lifespan',
                   details=dict(
                       site=site,
                       port=port,
                       not_valid_before=cert_obj.not_valid_before.isoformat(),
                       not_valid_after=cert_obj.not_valid_after.isoformat(),
                       max_validity_days=max_validity_days,
                       cert_validity_days=cert_validity.days))
        result = False
    else:
        show_open('Certificate has an insecure lifespan',
                  details=dict(
                      site=site,
                      port=port,
                      not_valid_before=cert_obj.not_valid_before.isoformat(),
                      not_valid_after=cert_obj.not_valid_after.isoformat(),
                      max_validity_days=max_validity_days,
                      cert_validity_days=cert_validity.days))
        result = True
    return result
Beispiel #13
0
def is_cert_cn_not_equal_to_site(site: str, port: int = PORT) -> bool:
    """
    Check if certificate Common Name (CN) is different from given sitename.

    Name in certificate should be coherent with organization name, see
    `REQ. 093 <https://fluidattacks.com/web/rules/093/>`_

    :param site: Site address.
    :param port: Port to connect to.
    """
    result = True
    try:
        with connect(site, port=port) as conn:
            __cert = conn.session.serverCertChain.x509List[0].bytes
            cert = ssl.DER_cert_to_PEM_cert(__cert)
    except socket.error:
        show_unknown('Port closed', details=dict(site=site, port=port))
        return False
    except tlslite.errors.TLSRemoteAlert as exc:
        show_unknown('Could not connect',
                     details=dict(site=site,
                                  port=port,
                                  error=str(exc).replace(':', ',')))
        return False
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        return False
    cert_obj = load_pem_x509_certificate(cert.encode('utf-8'),
                                         default_backend())
    cert_cn = \
        cert_obj.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[
            0].value.lower()

    wc_cert = '*.' + site.lower()

    domain = 'NONE'
    if cert_cn.startswith('*.'):
        domain = '.' + cert_cn.split('*.')[1].lower()

    if (site.lower() != cert_cn and wc_cert != cert_cn
            and not site.endswith(domain)):
        show_open('{} CN not equals to site'.format(cert_cn),
                  details=dict(site=site, port=port, cn=cert_cn))
        result = True
    else:
        show_close('{} CN equals to site'.format(cert_cn),
                   details=dict(site=site, port=port, cn=cert_cn))
        result = False
    return result
Beispiel #14
0
def is_cert_inactive(site: str, port: int = PORT) -> bool:
    """
    Check if certificate is no longer valid.

    Fails if end of validity date obtained from certificate
    is beyond the time of execution.

    :param site: Site address.
    :param port: Port to connect to.
    """
    result = True
    try:
        with connect(site, port=port) as conn:
            __cert = conn.session.serverCertChain.x509List[0].bytes
            cert = ssl.DER_cert_to_PEM_cert(__cert)
    except socket.error:
        show_unknown('Port closed', details=dict(site=site, port=port))
        return False
    except tlslite.errors.TLSRemoteAlert as exc:
        show_unknown('Could not connect',
                     details=dict(site=site,
                                  port=port,
                                  error=str(exc).replace(':', ',')))
        return False
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        return False
    cert_obj = load_pem_x509_certificate(cert.encode('utf-8'),
                                         default_backend())

    if cert_obj.not_valid_after > datetime.datetime.now():
        show_close('Certificate is still valid',
                   details=dict(
                       site=site,
                       port=port,
                       not_valid_after=cert_obj.not_valid_after.isoformat(),
                       current_time=datetime.datetime.now().isoformat()))
        result = False
    else:
        show_open('Certificate is expired',
                  details=dict(
                      site=site,
                      port=port,
                      not_valid_after=cert_obj.not_valid_after.isoformat(),
                      current_time=datetime.datetime.now().isoformat()))
        result = True
    return result
Beispiel #15
0
def _uses_sign_alg(site: str, alg: str, port: int) -> bool:
    """
    Check if the given hashing method was used in signing the site certificate.

    :param site: Address to connect to.
    :param alg: Hashing method to test.
    :param port: Port to connect to.
    """
    result = True

    try:
        with connect(site, port=port) as connection:
            __cert = connection.session.serverCertChain.x509List[0].bytes
            cert = ssl.DER_cert_to_PEM_cert(__cert)
    except socket.error:
        show_unknown('Port closed', details=dict(site=site, port=port))
        return False
    except tlslite.errors.TLSRemoteAlert as exc:
        show_unknown('Could not connect',
                     details=dict(site=site,
                                  port=port,
                                  error=str(exc).replace(':', ',')))
        return False
    except (tlslite.errors.TLSLocalAlert):
        show_unknown('Port doesn\'t support SSL',
                     details=dict(site=site, port=port))
        return False
    cert_obj = load_pem_x509_certificate(cert.encode('utf-8'),
                                         default_backend())

    sign_algorith = cert_obj.signature_hash_algorithm.name

    if alg in sign_algorith:
        show_open('Certificate has {} as signature algorithm'.format(
            sign_algorith.upper()),
                  details=dict(site=site, port=port))
        result = True
    else:
        show_close('Certificate does not use {} as signature algorithm'.format(
            alg.upper()),
                   details=dict(site=site,
                                port=port,
                                cert_algorithm=sign_algorith.upper()))
        result = False
    return result
Beispiel #16
0
def is_port_insecure(ipaddress: str, port: int) -> bool:
    """
    Check if a given port on an IP address is insecure.

    :param ipaddress: IP address to test.
    :param port: Port to connect to.
    """
    try:
        with ssl_helper.connect(ipaddress, port):
            show_close('Port is secure', details=dict(ip=ipaddress, port=port))
            return False
    except (ConnectionRefusedError, socket.timeout):
        show_unknown('Could not connect',
                     details=dict(ip=ipaddress, port=port))
        return False
    except (tlslite.errors.TLSIllegalParameterException,
            tlslite.errors.TLSLocalAlert):
        show_open('Port is not secure', details=dict(ip=ipaddress, port=port))
        return True
    except OverflowError:
        show_unknown('Bad arguments were given',
                     details=dict(ip=ipaddress, port=port))
        return False