Skip to content

Instantly share code, notes, and snippets.

@anthonykasza
Created November 16, 2023 15:44
Show Gist options
  • Save anthonykasza/be4f3dd2ae1fe5b7312b5682d293f1e1 to your computer and use it in GitHub Desktop.
Save anthonykasza/be4f3dd2ae1fe5b7312b5682d293f1e1 to your computer and use it in GitHub Desktop.
Forge a 3-way TCP handshake for pcap analysis
# The foundation for this script was provided by ChatGTP
# Zeek needs a TCP handshake to analyze a TLS stream.
# This script forges a handshake for each packet carrying a ClientHello record
# and writes the handshake, the ClientHello, and any ServerHellos to its own pcap
import sys
from scapy.all import *
def find_hellos(pcap_file):
load_layer("tls")
packets = rdpcap(pcap_file)
client_hello_packets = []
for packet in packets:
if packet.haslayer(TLS):
if packet[TLS].msg[0].msgtype == 1:
client_hello_packets.append(packet)
if packet[TLS].msg[0].msgtype == 2:
server_hello_packets.append(packet[IP] / packet[TCP] / packet[TLS])
return client_hello_packets, server_hello_packets
def create_handshake_packets(src_ip, dst_ip, src_port, dst_port, seq, ack):
syn = IP(src=src_ip, dst=dst_ip) / TCP(sport=src_port, dport=dst_port, flags='S', seq=seq-1)
syn_ack = IP(src=dst_ip, dst=src_ip) / TCP(sport=dst_port, dport=src_port, flags='SA', seq=ack-1, ack=seq)
# this assumes the ClientHello message is the first thing sent to the server after the handshake.
# it also assumes the TCP packet carrying the ClientHello message contains the final ACK flag
# for the 3-way. In the wild, a client may first respond with an ACK packet then a packet carrying DATA.
# this also will mess up any other analysis requiring the TCP handshake, such as JA4-L
return [syn, syn_ack]
def write_to_pcap(packets, filename):
wrpcap(filename, packets)
def main():
pcap_file = sys.argv[1]
client_hello_packets, server_hello_packets = find_hellos(pcap_file)
for i, packet in enumerate(client_hello_packets):
src_ip = packet[IP].src
dst_ip = packet[IP].dst
src_port = packet[TCP].sport
dst_port = packet[TCP].dport
seq = packet[TCP].seq
ack = packet[TCP].ack
new_pcap_name = f'{src_ip}:{src_port}_{dst_ip}:{dst_port}_{i}.pcap'
handshake_packets = create_handshake_packets(src_ip, dst_ip, src_port, dst_port, seq, ack)
raw = packet[IP] / packet[TCP] / packet[TLS]
# TODO - the script writes _all_ of the ServerHello packets to _each_ pcap file, regardless if the serverhello belongs to the stream of not
# consider indexing serverhellos packets in a dict with keys of [sorted([sip, dip]), sorted([sport, dport])]
write_to_pcap(handshake_packets + [raw] + server_hello_packets, new_pcap_name)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment