Beispiel #1
0
 def should_ADD_FINISHED(self):
     self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
     p = TLSFinished()
     self.cur_pkt.msg.append(p)
     self.socket.send(str(self.cur_pkt))
     self.cur_pkt = None
     raise self.ADD_FINISHED()
Beispiel #2
0
 def should_ADD_CKE_from_ADD_CLIENT_CERT(self):
     self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
     p = TLSClientKeyExchange()
     self.cur_pkt.msg.append(p)
     self.socket.send(str(self.cur_pkt))
     self.cur_pkt = None
     raise self.ADD_CKE()
Beispiel #3
0
    def PROCESS_DATA(self):
        """
        In the beginning, we return a small page with useful information.
        Then, we act as an echo server.
        """
        self.cur_pkt = self.msg_list[0]
        self.msg_list = self.msg_list[1:]

        recv_data = self.cur_pkt.data
        print "Received %s" % repr(recv_data)

        if recv_data.startswith("GET / HTTP/1."):
            header = "HTTP/1.1 200 OK\r\n"
            header += "Server: Scapy TLS Extension\r\n"
            header += "Content-type: text/html\r\n"
            header += "Content-length: %d\r\n\r\n"
            s = "Information on current TLS session:\n\n"
            s += "Local end      : %s:%d\n" % (self.local_ip, self.local_port)
            s += "Remote end     : %s:%d\n" % (self.remote_ip,
                                               self.remote_port)
            v = self.cur_session.advertised_tls_version
            v = "%s (0x%04x)" % (_tls_version[v], v)
            s += "TLS version    : %s\n" % v
            s += repr(self.cur_session.wcs)
            body = "<html><body><pre>%s</pre></body></html>\r\n\r\n" % s
            page = (header + body) % len(body)
        else:
            page = recv_data

        p = Raw(load=page)
        self.cur_pkt = TLS(type=23, msg=[p], tls_session=self.cur_session)
        self.socket.send(str(self.cur_pkt))
        raise self.FINISHED_SENT()
Beispiel #4
0
def build_client_hello(tls_version, cipher_suites, session_ticket=None):
    """
    Build a ClientHello with the given TLS version, cipher suite, and optional
    session ticket.
    """

    client_hello_record = None

    # Build TLS ClientHello
    if tls_version > 0x0002:
        extensions = None
        if session_ticket:
            extensions = [TLS_Ext_SessionTicket(ticket=session_ticket)]
        tls_client_hello = TLSClientHello(version=tls_version,
                                          gmt_unix_time=int(time.time()),
                                          random_bytes=randstring(28),
                                          sidlen=0,
                                          ciphers=cipher_suites,
                                          complen=1,
                                          ext=extensions)
        client_hello_record = TLS(msg=[tls_client_hello])
    else:
        # SSLv2 ClientHello
        sslv2_client_hello = SSLv2ClientHello(version=tls_version,
                                              sidlen=0,
                                              ciphers=cipher_suites)
        client_hello_record = SSLv2(msg=[sslv2_client_hello])

    return client_hello_record
Beispiel #5
0
 def should_ADD_CCS_from_ADD_CKE(self):
     self.cur_pkt = TLS(type=20, tls_session=self.cur_session, msg=[])
     p = TLSChangeCipherSpec()
     self.cur_pkt.msg.append(p)
     self.socket.send(str(self.cur_pkt))
     self.cur_pkt = None
     raise self.ADD_CCS()
Beispiel #6
0
    def handle(self):
        record_bytes = read_tls_record(self.rfile)
        record = TLS(record_bytes)

        ext_server_name = record.getlayer(TLS_Ext_ServerName)
        if ext_server_name == None:
            self.log_message("ServerName is missing from TLS record")
            return

        server_names = [
            str(s.servername, "ascii") for s in ext_server_name.servernames
        ]
        self.log_message(f"Server names: {server_names}")

        if len(server_names) == 0:
            self.log_message("List of server names is empty")
            return

        host = server_names[0]

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((host, 443))

        s.send(record_bytes)

        def read_client():
            s.send(read_tls_record(self.rfile))

        def read_remote():
            self.wfile.write(read_tls_record(s))

        sel = DefaultSelector()
        sel.register(self.rfile, EVENT_READ, read_client)
        sel.register(s, EVENT_READ, read_remote)

        got_read_error = False
        while not got_read_error:
            events = sel.select()
            for key, mask in events:
                try:
                    key.data()
                except ReadError:
                    got_read_error = True
                    break

        s.close()
Beispiel #7
0
 def NO_USABLE_CIPHERSUITE(self):
     """
     If there is no available cipher suite, close the session with an Alert.
     """
     print "No usable cipher suite, closing connection"
     self.cur_pkt = TLS(type=21, msg=[], tls_session=self.cur_session)
     p = TLSAlert(level=1, descr=0)
     self.cur_pkt.msg.append(p)
     self.socket.send(str(self.cur_pkt))
     self.cur_pkt = None
Beispiel #8
0
    def should_REPLY_TO_CH(self):
        """
        XXX Several enhancements needed here.

        Selecting a cipher suite should be no trouble as we already caught the
        None case previously. However, regarding the protocol version, we
        might want to try resending a ClientHello when the advertised
        version is not deemed satisfying.

        Then, the sending of ServerHello, Certificate, ServerKeyExchange and
        ServerHelloDone should be split into multiple states, in order for the
        user to overload only the ones he's interested in.

        Also, we do not manage extensions at all.
        """
        if isinstance(self.mykey, PrivKeyRSA):
            kx = "RSA"
        elif isinstance(self.mykey, PrivKeyECDSA):
            kx = "ECDSA"
        usable_suites = get_usable_ciphersuites(self.cur_pkt.ciphers, kx)
        c = usable_suites[0]
        if self.preferred_ciphersuite in usable_suites:
            c = self.preferred_ciphersuite

        comp = 0
        if self.cur_pkt.comp and 1 in self.cur_pkt.comp:
            comp = 1

        self.cur_session.advertised_tls_version = self.cur_pkt.version
        self.cur_session.tls_version = self.cur_pkt.version
        #XXX there should be some checks on this version from the ClientHello
        v = self.cur_session.tls_version
        print "\nVersion: " + _tls_version[v]
        print "Cipher suite: " + _tls_cipher_suites[c]

        self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])

        p = TLSServerHello(cipher=c, comp=[comp])
        self.cur_pkt.msg.append(p)

        p = TLSCertificate(certs=self.cur_session.server_certs)
        self.cur_pkt.msg.append(p)

        if not _tls_cipher_suites_cls[c].kx_alg.no_ske:
            p = TLSServerKeyExchange()
            self.cur_pkt.msg.append(p)

        p = TLSServerHelloDone()
        self.cur_pkt.msg.append(p)

        self.socket.send(str(self.cur_pkt))
        self.cur_pkt = None
        raise self.SENT_SH()
Beispiel #9
0
    def get_next_msg(self):
        """
        The purpose of the function is to make next message(s) available
        in self.msg_list. If the list is not empty, nothing is done. If
        not, in order to fill it, the function uses the data already
        available in self.remain from a previous call and waits till there
        are enough to dissect a TLS packet (expected length is in the 5
        first bytes of the packet). Once dissected, the content of the
        TLS packet (carried messages) is appended to self.msg_list.

        We have to grab enough data to dissect a TLS packet, i.e. at least
        5 bytes in order to access the expected length of the TLS packet.
        """

        if self.msg_list:  # a message is already available
            return

        self.socket.settimeout(5)
        retry = 5
        grablen = 5
        while retry and (grablen == 5 or len(self.remain) < grablen):
            if grablen == 5 and len(self.remain) >= 5:
                grablen = struct.unpack('!H', self.remain[3:5])[0] + 5
            if grablen == len(self.remain):
                break

            try:
                tmp = self.socket.recv(grablen - len(self.remain))
                if not tmp:
                    retry -= 1
                else:
                    self.remain += tmp
            except:
                retry -= 1

        if self.remain < 5 or len(self.remain) != grablen:
            # Remote peer is not willing to respond
            return

        # Instantiate TLS packet (record header only, at this point)
        p = TLS(self.remain, tls_session=self.cur_session)
        self.cur_session = p.tls_session
        self.remain = ""
        self.msg_list += p.msg

        while p.payload:
            if isinstance(p.payload, Raw):
                self.remain += p.payload.load
                p = p.payload
            elif isinstance(p.payload, TLS):
                p = p.payload
                self.msg_list += p.msg
Beispiel #10
0
 def add_record(self, is_sslv2=None, is_tls13=None, is_tls12=None):
     """
     Add a new TLS or SSLv2 or TLS 1.3 record to the packets buffered out.
     """
     if is_sslv2 is None and is_tls13 is None and is_tls12 is None:
         v = (self.cur_session.tls_version
              or self.cur_session.advertised_tls_version)
         if v in [0x0200, 0x0002]:
             is_sslv2 = True
         elif v >= 0x0304:
             is_tls13 = True
     if is_sslv2:
         self.buffer_out.append(SSLv2(tls_session=self.cur_session))
     elif is_tls13:
         self.buffer_out.append(TLS13(tls_session=self.cur_session))
     # For TLS 1.3 middlebox compatibility, TLS record version must
     # be 0x0303
     elif is_tls12:
         self.buffer_out.append(
             TLS(version="TLS 1.2", tls_session=self.cur_session))
     else:
         self.buffer_out.append(TLS(tls_session=self.cur_session))
Beispiel #11
0
 def WAIT_FOR_RESP2(self):
     self.socket.settimeout(10)
     s = self.socket.recv(100000)
     p = TLS(s, tls_session=self.cur_session)
     self.msg_list = p.msg
     while p.payload:
         if isinstance(p.payload, Raw):
             self.remain += p.payload.load
             p = p.payload
         elif isinstance(p.payload, TLS):
             p = p.payload
             self.msg_list += p.msg
     raise self.PREPROCESS_RESP2()
Beispiel #12
0
 def close_session(self):
     """
     We end the session properly after 2 seconds,
     with a TLS Alert (warning, close_notify).
     """
     time.sleep(2)
     self.cur_pkt = TLS(type=21, msg=[], tls_session=self.cur_session)
     p = TLSAlert(level=1, descr=0)
     self.cur_pkt.msg.append(p)
     try:
         self.socket.send(str(self.cur_pkt))
     except:
         print "Could not send termination Alert (maybe the server stopped)"
     self.cur_pkt = None
Beispiel #13
0
 def do_dissect_payload(self, s):
     """
     Try to dissect the following data as a TLS message.
     Note that overloading .guess_payload_class() would not be enough,
     as the TLS session to be used would get lost.
     """
     if s:
         try:
             p = TLS(s, _internal=1, _underlayer=self,
                     tls_session=self.tls_session)
         except KeyboardInterrupt:
             raise
         except Exception:
             p = conf.raw_layer(s, _internal=1, _underlayer=self)
         self.add_payload(p)
Beispiel #14
0
def banner2ja3c(banner: bytes) -> Optional[str]:
    # "lazy" import for scapy, as this import is slow.
    # TLS is assigned by the import statement, but pylint seems to miss it.
    global HAS_SCAPY, TLS  # pylint: disable=global-variable-not-assigned
    if HAS_SCAPY is None:
        try:
            # noqa: E402
            # pylint: disable=import-outside-toplevel
            from scapy.layers.tls.record import TLS  # type: ignore
        except ImportError:
            HAS_SCAPY = False
        else:
            HAS_SCAPY = True
    if not HAS_SCAPY:
        utils.LOGGER.warning("Scapy not found: cannot parse TLS banners")
        return None
    data = TLS(banner)  # type: ignore
    try:
        if data.type != 22:  # handshake
            return None
    except AttributeError:
        return None
    output = []
    for msg in data.msg:
        try:
            if msg.msgtype != 1:  # TLSClientHello
                continue
        except AttributeError:
            utils.LOGGER.warning("Cannot parse TLS message [%r]", msg)
            continue
        output.append(str(msg.version))
        output.append("-".join(
            str(c) for c in msg.ciphers or [] if c not in GREASE))
        output.append("-".join(
            str(e.type) for e in msg.ext or [] if e.type not in GREASE))
        ecsg: List[str] = []
        ecpf: List[str] = []
        for ext in msg.ext or []:
            if ext.type == 10:  # supported_groups / elliptic_curves
                ecsg.extend(str(g) for g in ext.groups if g not in GREASE)
            elif ext.type == 11:  # ec_point_formats
                ecpf.extend(str(p) for p in ext.ecpl if p not in GREASE)
        output.append("-".join(ecsg))
        output.append("-".join(ecpf))
        break
    if not output:
        return None
    return ",".join(output)
Beispiel #15
0
 def should_ADD_CV_from_ADD_CKE(self):
     """
     XXX Section 7.4.7.1 of RFC 5246 states that the CertificateVerify
     message is only sent following a client certificate that has signing
     capability (i.e. not those containing fixed DH params).
     We should verify that before adding the message. We should also handle
     the case when the Certificate message was empty.
     """
     if (not self.cert_req or self.mycert is None or self.mykey is None):
         return
     self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
     p = TLSCertificateVerify()
     self.cur_pkt.msg.append(p)
     self.socket.send(str(self.cur_pkt))
     self.cur_pkt = None
     raise self.ADD_CV()
Beispiel #16
0
    def send_recv_data(self):
        """
        XXX No live input from the user ; one unique send for now.
        XXX We might want not to send any ApplicationData message.
        XXX We do not wait very long for server answer.
        """
        txt = self.data or "GET /\r\n\r\n"  # GET HTTP/1.1\r\n\r\n"
        p = TLS(type=23, tls_session=self.cur_session, msg=[Raw(load=txt)])
        self.socket.send(str(p))
        print "Sent to server: \n%r" % txt

        self.get_next_msg(1, 0)
        if self.msg_list:
            p = self.msg_list[0]
            self.msg_list = self.msg_list[1:]
            if isinstance(p, Raw):
                print "Received from server: \n%s" % p.load
            else:
                print "Received from server: \n%s" % p
Beispiel #17
0
    def should_ADD_CLIENT_CERT(self):
        """
        If the server sent a CertificateRequest, we send a Certificate message.
        If no certificate is available, an empty Certificate message is sent:
        - this is a SHOULD in RFC 4346 (Section 7.4.6)
        - this is a MUST in RFC 5246 (Section 7.4.6)

        XXX We may want to add a complete chain.
        """
        if not self.cert_req:
            return
        certs = []
        if self.mycert:
            certs = [self.mycert]
        self.cur_pkt = TLS(tls_session=self.cur_session, msg=[])
        p = TLSCertificate(certs=certs)
        self.cur_pkt.msg.append(p)
        self.socket.send(str(self.cur_pkt))
        self.cur_pkt = None
        raise self.ADD_CLIENT_CERT()
Beispiel #18
0
Datei: ja3.py Projekt: ivre/ivre
def banner2ja3c(banner: bytes) -> Optional[str]:
    if not HAS_SCAPY:
        utils.LOGGER.warning("Scapy not found: cannot parse TLS banners")
        return None
    data = TLS(banner)
    try:
        if data.type != 22:  # handshake
            return None
    except AttributeError:
        return None
    output = []
    for msg in data.msg:
        try:
            if msg.msgtype != 1:  # TLSClientHello
                continue
        except AttributeError:
            utils.LOGGER.warning("Cannot parse TLS message [%r]", msg)
            continue
        output.append(str(msg.version))
        output.append("-".join(str(c) for c in msg.ciphers or [] if c not in GREASE))
        output.append(
            "-".join(str(e.type) for e in msg.ext or [] if e.type not in GREASE)
        )
        ecsg: List[str] = []
        ecpf: List[str] = []
        for ext in msg.ext or []:
            if ext.type == 10:  # supported_groups / elliptic_curves
                ecsg.extend(str(g) for g in ext.groups if g not in GREASE)
            elif ext.type == 11:  # ec_point_formats
                ecpf.extend(str(p) for p in ext.ecpl if p not in GREASE)
        output.append("-".join(ecsg))
        output.append("-".join(ecpf))
        break
    if not output:
        return None
    return ",".join(output)
Beispiel #19
0
    def get_next_msg(self, socket_timeout=2, retry=2):
        """
        The purpose of the function is to make next message(s) available in
        self.buffer_in. If the list is not empty, nothing is done. If not, in
        order to fill it, the function uses the data already available in
        self.remain_in from a previous call and waits till there are enough to
        dissect a TLS packet. Once dissected, the content of the TLS packet
        (carried messages, or 'fragments') is appended to self.buffer_in.

        We have to grab enough data to dissect a TLS packet. We start by
        reading the first 2 bytes. Unless we get anything different from
        \\x14\\x03, \\x15\\x03, \\x16\\x03 or \\x17\\x03 (which might indicate
        an SSLv2 record, whose first 2 bytes encode the length), we retrieve
        3 more bytes in order to get the length of the TLS record, and
        finally we can retrieve the remaining of the record.
        """
        if self.buffer_in:
            # A message is already available.
            return

        self.socket.settimeout(socket_timeout)
        is_sslv2_msg = False
        still_getting_len = True
        grablen = 2
        while retry and (still_getting_len or len(self.remain_in) < grablen):
            if not is_sslv2_msg and grablen == 5 and len(self.remain_in) >= 5:
                grablen = struct.unpack('!H', self.remain_in[3:5])[0] + 5
                still_getting_len = False
            elif grablen == 2 and len(self.remain_in) >= 2:
                byte0 = struct.unpack("B", self.remain_in[0])[0]
                byte1 = struct.unpack("B", self.remain_in[1])[0]
                if (byte0 in _tls_type) and (byte1 == 3):
                    # Retry following TLS scheme. This will cause failure
                    # for SSLv2 packets with length 0x1{4-7}03.
                    grablen = 5
                else:
                    # Extract the SSLv2 length.
                    is_sslv2_msg = True
                    still_getting_len = False
                    if byte0 & 0x80:
                        grablen = 2 + 0 + ((byte0 & 0x7f) << 8) + byte1
                    else:
                        grablen = 2 + 1 + ((byte0 & 0x3f) << 8) + byte1
            elif not is_sslv2_msg and grablen == 5 and len(self.remain_in) >= 5:
                grablen = struct.unpack('!H', self.remain_in[3:5])[0] + 5

            if grablen == len(self.remain_in):
                break

            try:
                tmp = self.socket.recv(grablen - len(self.remain_in))
                if not tmp:
                    retry -= 1
                else:
                    self.remain_in += tmp
            except:
                retry -= 1

        if self.remain_in < 2 or len(self.remain_in) != grablen:
            # Remote peer is not willing to respond
            return

        p = TLS(self.remain_in, tls_session=self.cur_session)
        self.cur_session = p.tls_session
        self.remain_in = ""
        if isinstance(p, SSLv2) and not p.msg:
            p.msg = Raw("")
        if self.cur_session.tls_version < 0x0304:
            self.buffer_in += p.msg
        else:
            if isinstance(p, TLS13):
                self.buffer_in += p.inner.msg
            else:
                # should be TLS13ServerHello only
                self.buffer_in += p.msg

        while p.payload:
            if isinstance(p.payload, Raw):
                self.remain_in += p.payload.load
                p = p.payload
            elif isinstance(p.payload, TLS):
                p = p.payload
                if self.cur_session.tls_version < 0x0304:
                    self.buffer_in += p.msg
                else:
                    self.buffer_in += p.inner.msg
Beispiel #20
0
async def get_sros_certificate(address, port, timeout=3):
    """
    Function to connect to a SROS Node, simulate the TLS handshake, and get it's server certificate on the process.
    :param address: Address of the node.
    :param port: Port of the node.
    :param timeout: Timeout for the connection.
    :return: A tuple containing the address, port and certificate if found, otherwise,
    a tuple containing address, port and None.
    """
    client_hello = TLS(
        version='TLS 1.0',
        msg=TLSClientHello(
            ciphers=[
                49200, 49196, 49202, 49198, 49199, 49195, 49201, 49197, 165,
                163, 161, 159, 164, 162, 160, 158, 49192, 49188, 49172, 49162,
                49194, 49190, 49167, 49157, 107, 106, 105, 104,
                57, 56, 55, 54, 49191, 49187, 49171, 49161, 49193, 49189,
                49166, 49156, 103, 64, 63, 62, 51, 50, 49, 48, 136, 135, 134,
                133, 69, 68, 67, 66, 49170, 49160, 49165, 49155,
                22, 19, 16, 13, 157, 156, 61, 53, 60, 47, 132, 65, 10, 255
            ],
            comp=[0],
            gmt_unix_time=12345566,
            ext=[
                TLS_Ext_SupportedGroups(
                    groups=[23, 25, 28, 27, 24, 26, 22, 14, 13, 11, 12, 9, 10
                            ]),
                TLS_Ext_SupportedPointFormat(ecpl=[0, 1, 2]),
                TLS_Ext_SignatureAlgorithms(sig_algs=[
                    1537, 1538, 1539, 1281, 1282, 1283, 1025, 1026, 1027, 769,
                    770, 771, 513, 514, 515
                ]),
                TLS_Ext_Heartbeat(heartbeat_mode=1),
                TLS_Ext_Padding(padding=212 * b'\x00')
            ]))

    tls_header = b'\x16\x03\x03'
    server_hello_done = b'\x0e\x00\x00\x00'
    received_data = b''
    is_sros = True
    writer = None
    try:
        conn = asyncio.open_connection(str(address),
                                       port,
                                       loop=asyncio.get_event_loop())
        reader, writer = await asyncio.wait_for(conn, timeout=timeout)
        writer.write(bytes(client_hello))
        await writer.drain()
        while received_data[-4:] != server_hello_done:
            received_data += await asyncio.wait_for(reader.read(1024),
                                                    timeout=3)
            if received_data[:3] != tls_header:
                is_sros = False
                break
    except Exception as e:
        logger.error('[-] Error connecting to host ' + str(address) + ': ' +
                     str(e) + '\n\tNot a SROS host')
        return address, port, None
    else:
        if is_sros:
            server_hello = TLS(received_data)
            cert = server_hello.payload.msg[0].certs[0][1]
            logger.warning('[+] SROS host found!!!')
            return address, port, cert
    finally:
        if writer:
            writer.close()
            await writer.wait_closed()
    return address, port, None
Beispiel #21
0
 def should_SEND_FINISHED(self):
     p = TLSFinished()
     self.cur_pkt = TLS(tls_session=self.cur_session, msg=[p])
     self.socket.send(str(self.cur_pkt))
     self.cur_pkt = None
     raise self.FINISHED_SENT()
Beispiel #22
0
 def should_SEND_CCS(self):
     ccs = TLSChangeCipherSpec()
     self.cur_pkt = TLS(type=20, msg=[ccs], tls_session=self.cur_session)
     self.socket.send(str(self.cur_pkt))
     self.cur_pkt = None
     raise self.SEND_CCS()
Beispiel #23
0
    def decryptTLSStream(self):
        """
        Generator function that decrypts an RDP stream that uses TLS.
        """

        tpktParser = TPKTParser()
        tls = None
        clientRandom = None
        serverRandom = None
        currentTimeStamp = None
        reconstructingRecord = False
        savedRecord = None
        savedPayload = b""
        tlsKeyGenerated = False

        for packet in self.packets:
            ip = packet.getlayer(IP)
            tcp = packet.getlayer(TCP)

            if len(tcp.payload) == 0 or tcp.flags & TCPFlags.PSH == 0:
                continue

            currentTimeStamp = packet.time
            currentSrc = ip.src
            currentDst = ip.dst

            # The first couple messages don't use TLS. Check if it's one of those messages and output it as is.
            if hasattr(tcp, "load") and tpktParser.isTPKTPDU(tcp.load):
                yield PCAPStream.output(tcp.load, currentTimeStamp, ip.src,
                                        ip.dst)
                continue

            # Create the TLS session context.
            if not tls:
                tls = tlsSession(
                    ipsrc=ip.src,
                    ipdst=ip.dst,
                    sport=tcp.sport,
                    dport=tcp.dport,
                    connection_end="server",
                )

            if tls.ipsrc != ip.src:
                tls = tls.mirror()

            # Pass every TLS message through our own custom session so the state is kept properly
            record = packet[TLS]
            record = TLS(bytes(record), tls_session=tls)

            for msg in record.msg:
                if isinstance(msg, TLSClientHello):
                    clientRandom = pkcs_i2osp(msg.gmt_unix_time,
                                              4) + msg.random_bytes
                elif isinstance(msg, TLSServerHello):
                    serverRandom = pkcs_i2osp(msg.gmt_unix_time,
                                              4) + msg.random_bytes
                elif isinstance(msg, TLSNewSessionTicket):
                    # Session established, set master secret.
                    tls.rcs.derive_keys(
                        client_random=clientRandom,
                        server_random=serverRandom,
                        master_secret=self.masterSecret,
                    )

                    tls.wcs.derive_keys(
                        client_random=clientRandom,
                        server_random=serverRandom,
                        master_secret=self.masterSecret,
                    )

                    tlsKeyGenerated = True
                elif isinstance(msg, TLSApplicationData):
                    yield PCAPStream.output(msg.data, currentTimeStamp, ip.src,
                                            ip.dst)
Beispiel #24
0
def build_tls_record(tls_data):
    """
    Build a TLS record using the given data.
    """

    return TLS(tls_data)
Beispiel #25
0
def build_tls_record_with_message(message):
    """
    Build a TLS record using the given message parameter.
    """

    return TLS(msg=[message])
Beispiel #26
0
    def get_next_msg(self, socket_timeout=2, retry=2):
        """
        The purpose of the function is to make next message(s) available in
        self.buffer_in. If the list is not empty, nothing is done. If not, in
        order to fill it, the function uses the data already available in
        self.remain_in from a previous call and waits till there are enough to
        dissect a TLS packet. Once dissected, the content of the TLS packet
        (carried messages, or 'fragments') is appended to self.buffer_in.

        We have to grab enough data to dissect a TLS packet. We start by
        reading the first 2 bytes. Unless we get anything different from
        \\x14\\x03, \\x15\\x03, \\x16\\x03 or \\x17\\x03 (which might indicate
        an SSLv2 record, whose first 2 bytes encode the length), we retrieve
        3 more bytes in order to get the length of the TLS record, and
        finally we can retrieve the remaining of the record.
        """
        if self.buffer_in:
            # A message is already available.
            return

        self.socket.settimeout(socket_timeout)
        is_sslv2_msg = False
        still_getting_len = True
        grablen = 2
        while retry and (still_getting_len or len(self.remain_in) < grablen):
            if not is_sslv2_msg and grablen == 5 and len(self.remain_in) >= 5:
                grablen = struct.unpack('!H', self.remain_in[3:5])[0] + 5
                still_getting_len = False
            elif grablen == 2 and len(self.remain_in) >= 2:
                byte0, byte1 = struct.unpack("BB", self.remain_in[:2])
                if (byte0 in _tls_type) and (byte1 == 3):
                    # Retry following TLS scheme. This will cause failure
                    # for SSLv2 packets with length 0x1{4-7}03.
                    grablen = 5
                else:
                    # Extract the SSLv2 length.
                    is_sslv2_msg = True
                    still_getting_len = False
                    if byte0 & 0x80:
                        grablen = 2 + 0 + ((byte0 & 0x7f) << 8) + byte1
                    else:
                        grablen = 2 + 1 + ((byte0 & 0x3f) << 8) + byte1
            elif not is_sslv2_msg and grablen == 5 and len(
                    self.remain_in) >= 5:  # noqa: E501
                grablen = struct.unpack('!H', self.remain_in[3:5])[0] + 5

            if grablen == len(self.remain_in):
                break

            try:
                tmp = self.socket.recv(grablen - len(self.remain_in))
                if not tmp:
                    retry -= 1
                else:
                    self.remain_in += tmp
            except Exception:
                self.vprint("Could not join host ! Retrying...")
                retry -= 1

        if len(self.remain_in) < 2 or len(self.remain_in) != grablen:
            # Remote peer is not willing to respond
            return

        p = TLS(self.remain_in, tls_session=self.cur_session)
        self.cur_session = p.tls_session
        self.remain_in = b""
        if isinstance(p, SSLv2) and not p.msg:
            p.msg = Raw("")
        if self.cur_session.tls_version is None or \
           self.cur_session.tls_version < 0x0304:
            self.buffer_in += p.msg
        else:
            if isinstance(p, TLS13):
                self.buffer_in += p.inner.msg
            else:
                # should be TLS13ServerHello only
                self.buffer_in += p.msg

        while p.payload:
            if isinstance(p.payload, Raw):
                self.remain_in += p.payload.load
                p = p.payload
            elif isinstance(p.payload, TLS):
                p = p.payload
                if self.cur_session.tls_version is None or \
                   self.cur_session.tls_version < 0x0304:
                    self.buffer_in += p.msg
                else:
                    self.buffer_in += p.inner.msg
Beispiel #27
0
 def PREPARE_FIRST_PKT(self):
     self.cur_pkt = TLS(tls_session=self.cur_session)