python dpkt SSL 流tcp payload(从三次握手开始到application data)和证书提取

使用Python的dpkt库解析pcap文件,详细提取TCP负载和SSL证书信息,包括三次握手到应用数据的过程,同时导出证书ID。
摘要由CSDN通过智能技术生成

 

# coding: utf-8
#!/usr/bin/env python

from __future__ import absolute_import
from __future__ import print_function
import traceback
import argparse
import ipaddress
from binascii import hexlify
import socket
import struct
import sys
import dpkt
import textwrap
import os
from asn1crypto import x509
from dpkt import ssl, Packet
import pickle
from constants import PRETTY_NAMES
from cert_filter import CertFilter


global encrypted_streams
encrypted_streams = []  # change_cipher
global ssl_servers_certs
ssl_servers_certs = {}
global ssl_servers_with_client_hello
ssl_servers_with_client_hello = set()
global client_hello_set
client_hello_set = set()

global server_ip_set
server_ip_set = set()

global buffer
buffer = {}
need_more_parse = False


def tls_multi_factory_new(buf):
    """
    Attempt to parse one or more TLSRecord's out of buf
    :param buf: string containing SSL/TLS messages. May have an incomplete record on the end
    :return:  [TLSRecord] int, total bytes consumed, != len(buf) if an incomplete record was left at the end.
    Raises SSL3Exception.
    """
    i, n = 0, len(buf)
    msgs = []

    while i + 5 <= n:
        v = buf[i + 1:i + 3]
        if v in ssl.SSL3_VERSION_BYTES:
            try:
                msg = ssl.TLSRecord(buf[i:])
                msgs.append(msg)
            except dpkt.NeedData:
                break
        else:
            if i == 0:  ############################################ added
                raise ssl.SSL3Exception('Bad TLS version in buf: %r' % buf[i:i + 5])
            else:
                break

        i += len(msg)

    return msgs, i


class FlowDirection(object):
    OUT = 1
    IN = 2
    UNKNOWN = 3


class Extension(object):
    """
    Encapsulates TLS extensions.
    """

    def __init__(self, payload):
        self._type_id, payload = unpacker('H', payload)
        self._type_name = pretty_name('extension_type', self._type_id)
        self._length, payload = unpacker('H', payload)
        # Data contains an array with the 'raw' contents
        self._data = None
        # pretty_data contains an array with the 'beautified' contents
        self._pretty_data = None
        if self._length > 0:
            self._data, self._pretty_data = parse_extension(payload[:self._length],
                                                            self._type_name)

    def __str__(self):
        # Prints out data array in textual format
        return '{0}: {1}'.format(self._type_name, self._pretty_data)


class OP:
    CHECK_TLS_PACKET = 1
    MERGE_TLS_PACKET = 2


def analyze_packet(_timestamp, packet, nth, op):
    """
    Main analysis loop for pcap.
    """
    eth = dpkt.ethernet.Ethernet(packet)
    if isinstance(eth.data, dpkt.ip.IP):
        # print("timestamp:", _timestamp, "debug")
        parse_ip_packet(eth.data, nth, _timestamp, op)


def parse_arguments():
    """
    Parses command line arguments.
    """
    global filename
    global verboseprint
    global output_file
    global is_white_sample
    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=textwrap.dedent('''\
Captures, parses and shows TLS Handshake packets
Copyright (C) 2015 Peter Mosmans [Go Forward]
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.'''))
    parser.add_argument('-r', '--read', metavar='FILE', action='store',
                        help='read from file (don\'t capture live packets)')
    parser.add_argument('-v', '--verbose', action='store_true',
                        help='increase output verbosity')
    parser.add_argument('-t', '--is_white_sample', action='store_true',
                        help='is white sample?')
    parser.add_argument('-o', '--output', action='store',
                        help='output file')
    args = parser.parse_args()

    if args.verbose:
        def verboseprint(*args):
            print('# ', end="")
            for arg in args:
                print(arg, end="")
            print()
    else:
        verboseprint = lambda *a: None
    if args.is_white_sample:
        print("OK, process white sample data.")
        is_white_sample = True
    else:
        print("OK, process black sample data.")
        is_white_sample = False
    filename = None
    if args.read:
        filename = args.read
    output_file = "demo_output.pickle"
    if args.output:
        output_file = args.output


def parse_ip_packet(ip, nth, timestamp, op):
    """
    Parses IP packet.
    """
    sys.stdout.flush()
    if isinstance(ip.data, dpkt.tcp.TCP):
        # print("****TCP packet found****", "tcp payload:", list(ip.data.data))
        """
        try:
            tls = dpkt.ssl.TLS(ip.data.data)
            if len(tls.records) < 1:
                return
        except Exception as e:
            print(e)
            return
        """
        parse_tcp_packet(ip, nth, timestamp, op)


# TLS  version
def check_tls_version(data):
    version2 = False
    version3 = False

    if len(data) > 2:
        # ssl
        tmp = struct.unpack("bbb", data[0:3])
    else:
        return version2, version3

    # SSL v2. OR Message body too short.
    if (tmp[0] & 0x80 == 0x80) and (((tmp[0] & 0x7f) << 8 | tmp[1]) > 9):
        version2 = True
    elif (tmp[1] != 3) or (tmp[2] > 3):  # 版本,SSL 3.0 or TLS 1.0, 1.1 and 1.2
        version3 = False
    elif (tmp[0] < 20) or (tmp[0] > 23):  # 类型错误
        pass
    else:
        version3 = True

    return version2, version3


def parse_tcp_packet(ip, nth, timestamp, op):
    """
    Parses TCP packet.
    """
    record_server_ip(ip)
    stream = ip.data.data
    if len(stream):
        record_data_flow(ip, stream, nth, timestamp)


# def record_server_ip(ip):
#     """
# >>> int(ipaddress.IPv4Address('192.168.0.1'))
# 3232235521
# >>> int(ipaddress.IPv4Address('0.0.0.1'))
# 1
# >>> int(ipaddress.IPv4Address('0.0.1.1'))
# 257
#     """
#     src_ip = socket.inet_ntoa(ip.src)
#     dst_ip = socket.inet_ntoa(ip.dst)
#     # 这里使用一个确定规则(小ip作为源),把相同方向的数据汇聚到一起
#     if int(ipaddress.IPv4Address(src_ip)) < int(ipaddress.IPv4Address(dst_ip)):
#         connection_key = "{}-{}".format(dst_ip, src_ip)
#         global server_ip_set
#         if connection_key not in server_ip_set:
#             server_ip_set.add(connection_key)
#             buffer[connection_key] = [{"out":[], "in":[]}]


def record_server_ip(ip):
    src_ip = '{0}:{1}'.format(socket.inet_ntoa(ip.src), ip.data.sport)
    dst_ip = '{0}:{1}'.format(socket.inet_ntoa(ip.dst), ip.data.dport)
    tcp = ip.data
    fin_flag = ( tcp.flags & dpkt.tcp.TH_FIN ) != 0
    syn_flag = ( tcp.flags & dpkt.tcp.TH_SYN ) != 0
    rst_flag = ( tcp.flags & dpkt.tcp.TH_RST ) != 0
    psh_flag = ( tcp.flags & dpkt.tcp.TH_PUSH) != 0
    ack_flag = ( tcp.flags & dpkt.tcp.TH_ACK ) != 0
    urg_flag = ( tcp.flags & dpkt.tcp.TH_URG ) != 0
    ece_flag = ( tcp.flags & dpkt.tcp.TH_ECE ) != 0
    cwr_flag = ( tcp.flags & dpkt.tcp.TH_CWR ) != 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值