1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
#!/usr/bin/env python3
import argparse
import random
from scapy.all import *
# msg_type: 1 (Client Hello)
# length: 47
# client_version: 1.2
# random: 32 bytes
# session_id: empty
# cipher_suite[1]: 0x002F (TLS_RSA_WITH_AES_128_CBC_SHA)
# compression_method[1]: null
# extensions[1]: 0xAAAA (GREASE) with two values (will be used as identifier)
clientHelloMsg = bytes([
0x01,
0x00, 0x00, 0x31,
0x03, 0x03,
]) + 32 * b'3' + bytes([
0x00,
0x00, 0x02, 0x00, 0x2f,
0x01, 0x00,
0x00, 0x06, 0xaa, 0xaa, 0x00, 0x02,
0x00, 0x00
])
assert len(clientHelloMsg) == 53
clientHelloMsgBase = clientHelloMsg[:-2]
def CH(num : int):
'''Returns a Client Hello message with some identifier.'''
return clientHelloMsgBase + num.to_bytes(2, 'big')
def TLSRecord(data):
# Handshake (22), TLSv1.0
return b'\x16\x03\x01' + len(data).to_bytes(2, 'big') + data
parser = argparse.ArgumentParser()
parser.add_argument('--seed', type=int)
parser.add_argument('--count', type=int, default=256, help='Streams count')
parser.add_argument('output_file')
args = parser.parse_args()
if args.seed is not None:
random.seed(args.seed)
# Pick a number of messages per stream such that at least the case is triggered
# where a record contains the end of a message, a full message and the start of
# another message. A lot more than three per record will likely not be useful
# since it does not trigger reassembly.
hsPerStream = 10
maxRecordSize = len(clientHelloMsg) * 4
# Fragment handshake message over TLS records,
# fragment TLS records over TCP segments.
packets = []
for i in range(args.count):
hs = b''.join(CH(hsPerStream * i + j + 1) for j in range(hsPerStream))
seq = 0x1000
while hs:
# Does not matter that n > maxRecordSize, it is capped anyway.
n = random.randint(1, maxRecordSize)
recordData, hs = hs[:n], hs[n:]
seg = TLSRecord(recordData)
pkt = IP()/TCP(flags='A', seq=seq, sport=0xc000 + i, dport=443)/seg
packets.append(pkt)
seq += len(seg)
wrpcap(args.output_file, packets)
r"""
Test:
tshark -r hs-frag.pcapng -Tfields -Y tls.handshake.extension.data -e tls.handshake.extension.data | tr , '\n'
Expected result: for a given 'count' streams, expect hexadecimal numbers 0001 up
to and including 10*count. E.g. for --count=10 the output should match:
printf '%004x\n' {1..100}
"""
|