From 6d4f5080c572e787018e55e7a9ef5312b36d0fa4 Mon Sep 17 00:00:00 2001 From: Hanno Heinrichs Date: Wed, 3 Feb 2016 23:44:32 +0100 Subject: [PATCH] fix scsv detection --- sslscan/module/rating/builtin.py | 9 +++++ sslscan/module/report/terminal.py | 2 +- sslscan/module/scan/__init__.py | 2 +- sslscan/module/scan/server_scsv.py | 57 ++++++++++++++++++++---------- 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/sslscan/module/rating/builtin.py b/sslscan/module/rating/builtin.py index acda803..051acda 100644 --- a/sslscan/module/rating/builtin.py +++ b/sslscan/module/rating/builtin.py @@ -83,5 +83,14 @@ def __init__(self, **kwargs): ) ) + self.add_rule( + RatingRule( + "server.security.scsv", + rules=[ + lambda v, i, kb: 1 if v is True else None + ] + ) + ) + modules.register(BuiltIn_0_5) diff --git a/sslscan/module/report/terminal.py b/sslscan/module/report/terminal.py index 7769f34..b5a92a9 100644 --- a/sslscan/module/report/terminal.py +++ b/sslscan/module/report/terminal.py @@ -426,7 +426,7 @@ def _print_server_security(self, kb): ) tmp_value = "-" if scsv_supported is None: - tmp_value = "unkown" + tmp_value = "unknown" elif scsv_supported is True: tmp_value = "supported" elif scsv_supported is False: diff --git a/sslscan/module/scan/__init__.py b/sslscan/module/scan/__init__.py index e5cc16e..03d1169 100644 --- a/sslscan/module/scan/__init__.py +++ b/sslscan/module/scan/__init__.py @@ -665,11 +665,11 @@ def _default_stop_condition(record, records): record = conn_tls.pop_record() self.parse_tls_server_records_hooks.call(record) + records.append(record) if isinstance(record, Alert): if record.level == 2: return records - records.append(record) if stop_condition(record, records): run = False diff --git a/sslscan/module/scan/server_scsv.py b/sslscan/module/scan/server_scsv.py index f4e4eca..4bbec7b 100644 --- a/sslscan/module/scan/server_scsv.py +++ b/sslscan/module/scan/server_scsv.py @@ -1,15 +1,12 @@ -from datetime import datetime - from sslscan import modules from sslscan.module.scan import BaseScan import flextls -from flextls.exception import NotEnoughData from flextls.field import CipherSuiteField from flextls.protocol.handshake import Handshake, ServerHello -from flextls.protocol.record import SSLv3Record from flextls.protocol.alert import Alert import six +from sslscan.exception import Timeout if six.PY2: import socket @@ -28,11 +25,10 @@ def __init__(self, **kwargs): BaseScan.__init__(self, **kwargs) def _connect_with_scsv(self, protocol_version, cipher_suites): - def hook_cipher_suites(record): - cipher_suites = flextls.registry.tls.cipher_suites[:] - for cipher_suite in cipher_suites: + def hook_cipher_suites(record, cipher_suites=None): + for i in cipher_suites: cipher = CipherSuiteField() - cipher.value = cipher_suite.id + cipher.value = i record.payload.cipher_suites.append(cipher) cipher = CipherSuiteField() @@ -42,11 +38,32 @@ def hook_cipher_suites(record): return record def stop_condition(record, records): - return isinstance(record, Handshake) and \ - isinstance(record.payload, ServerHello) + return (isinstance(record, Handshake) and + isinstance(record.payload, ServerHello)) ver_major, ver_minor = flextls.helper.get_tls_version(protocol_version) + is_dtls = False + if protocol_version & flextls.registry.version.DTLS != 0: + is_dtls = True + + if is_dtls: + self.build_dtls_client_hello_hooks.connect( + hook_cipher_suites, + name="cipher_suites", + args={ + "cipher_suites": cipher_suites + } + ) + else: + self.build_tls_client_hello_hooks.connect( + hook_cipher_suites, + name="cipher_suites", + args={ + "cipher_suites": cipher_suites + } + ) + records = self.connect( protocol_version, stop_condition=stop_condition @@ -54,17 +71,15 @@ def stop_condition(record, records): if records is None: return None - server_hello = None for record in records: if isinstance(record, Handshake): if isinstance(record.payload, ServerHello): - if record.version.major == ver_major and \ - record.version.minor == ver_minor: + if record.payload.version.major == ver_major and \ + record.payload.version.minor == ver_minor: return False - elif isinstance(record.payload, Alert): - if record.payload.level == 2 and \ - record.payload.description == 86: + elif isinstance(record, Alert): + if record.level == 2 and record.description == 86: return True def run(self): @@ -87,12 +102,18 @@ def run(self): if scsv_cur_status is None: continue - + if scsv_cur_status is True: kb.set("server.security.scsv", True) break - if scsv_status is False and scsv_cur_status is False: + # At least two protocol versions must reach a ServerHello in + # order to falsify SCSV security. Otherwise, if we + # coincidentally use the highest protocol version that the + # server supports, the server has to proceed with the + # handshake, even if the SCSV suite is present (see RFC 7507, + # section 3). + if scsv_status is False and scsv_cur_status is False: kb.set("server.security.scsv", False) break