Created
November 16, 2023 15:44
-
-
Save anthonykasza/be4f3dd2ae1fe5b7312b5682d293f1e1 to your computer and use it in GitHub Desktop.
Forge a 3-way TCP handshake for pcap analysis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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