Search code examples
pythoncwiresharktls1.2packet

how to make a self made TLS packet appear as tls in Wireshark and not as data


Lately I have started implementing TLS for the sport as a fun project and I'm currently trying to self make and send locally a client hello TLS packet (a minimal one).

When observed via the loopback interface in Wireshark it appears as pure data instead of a tls layer with all of the various fields and after lots of trying I decided to ask here the following questions:

  1. What's the difference between my self made packet and a real TLS client hello one?
  2. How does Wireshark selectively makes one appear as a TLS layered instead of pure data, is there an identifier field in the packet that declares it as pure data or a TLS layered one?
  3. How can I make my packet to appear as a client hello TLS packet instead of pure data?

Here is my server and client that send basically my c code output (remember that they are not made for real TLS handling but just to show the packet in Wireshark):

server.py

import socket

TCP_IP = '0.0.0.0' 
TCP_PORT = 2004

tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
tcpServer.bind((TCP_IP, TCP_PORT)) 
tcpServer.listen(4)
(conn, (ip,port)) = tcpServer.accept()

client.py

import socket

host = "127.0.0.1"
port = 2004
BUFFER_SIZE = 2000 

tcpClientA = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
tcpClientA.connect((host, port))

tcpClientA.send(b"\x16\x03\x01\x00\xa5\x01\xa1\x00\x00\x03\x03\x31\x32\x33\x34\x35\x36\x37\x38\x39\x61\x73\x64\x66\x67\x68\x6a\x6b\x6c\x7a\x78\x63\x76\x62\x6e\x6d\x61\x73\x64\x66\x67\x68\x6a\x00\x20\x00\xcc\xa8\xcc\xa9\xc0\x2f\xc0\x30\xc0\x2b\xc0\x2c\xc0\x13\xc0\x09\xc0\x14\xc0\x0a\x00\x9c\x00\x9d\x00\x2f\x00\x35\xc0\x12\x00\x0a")

this is my c code for creating the packet it shows that I have set all of the necessary client hello TLS fields for Wireshark to present (In addition I used the following site as guidance https://tls.ulfheim.net/) :

#include <stdint.h>
#include <stdio.h>
#include <string.h>

struct __attribute__((__packed__)) record {
    // record layer
    uint8_t  record_type;
    uint16_t version;
    uint16_t length;
    
    // handshake layer
    uint8_t  handshake_type;
    char     hello_length[3];
    
    // client version
    uint16_t tls_version;
    
    // client random
    char     client_random[32];
    
    // session id
    uint8_t  session_id;
    
    // cipher suites
    uint16_t suites_length;
    uint16_t suites[1000];

    
};

void print_struct(struct record r)
{
    unsigned char packet[sizeof(r)] = {0x00};
    memcpy(packet, &r, sizeof(r));
    
    for(int i = 0; i < sizeof(packet); i++) {
        if(packet[i] != 0xff) {
            printf("%02x", packet[i]);
        }
    }
}

int main()
{
    struct record client_hello = {0};
    
    client_hello.record_type = 0x16;
    client_hello.version = 0x0103;
    client_hello.length = 0xA500;
    
    client_hello.handshake_type = 0x01;
    client_hello.hello_length[0] = 0xA1;
    client_hello.hello_length[1] = 0x00;
    client_hello.hello_length[2] = 0x00;
    
    client_hello.tls_version = 0x0303;
    
    memcpy(client_hello.client_random, "123456789asdfghjklzxcvbnmasdfghj", 32);
    
    client_hello.session_id = 0x00;
    client_hello.suites_length = 32;
    
    uint16_t arr[] = {0xa8cc, 0xa9cc, 0x2fc0, 0x30c0, 0x2bc0, 0x2cc0, 0x13c0, 0x09c0, 0x14c0, 0x0ac0, 0x9c00, 0x9d00, 0x2f00, 0x3500, 0x12c0, 0x0a00};
    memset(client_hello.suites, 0xffff, sizeof(client_hello.suites));
    memcpy(client_hello.suites, arr, sizeof(arr));

    print_struct(client_hello);
    
    return 0;
}  

This is how Wireshark presents the sent self crafted TLS client hello packet:

0000   02 00 00 00 45 00 00 76 74 c5 40 00 80 06 00 00   ....E..vt.@.....
0010   7f 00 00 01 7f 00 00 01 d9 2f 07 d4 7f 69 9a d9   ........./...i..
0020   99 2a 47 85 50 18 27 f9 03 da 00 00 16 03 01 00   .*G.P.'.........
0030   a5 01 a1 00 00 03 03 31 32 33 34 35 36 37 38 39   .......123456789
0040   61 73 64 66 67 68 6a 6b 6c 7a 78 63 76 62 6e 6d   asdfghjklzxcvbnm
0050   61 73 64 66 67 68 6a 00 20 00 cc a8 cc a9 c0 2f   asdfghj. ....../
0060   c0 30 c0 2b c0 2c c0 13 c0 09 c0 14 c0 0a 00 9c   .0.+.,..........
0070   00 9d 00 2f 00 35 c0 12 00 0a                     .../.5....

how it appears in wire shark

This is a screen shot of how I want it to be shown:

enter image description here


Solution

  • For starters, the TLS length field is wrong. Wireshark's TCP dissector indicates that the TCP payload length is 78 bytes; yet the TLS length is 165 (0x00a5), and thus can't be correct. Also, the handshake length is wrong too. Try changing this:

    0030   a5 01 a1 00 00 03 03 31 32 33 34 35 36 37 38 39   .......123456789
    

    to this:

    0030   49 01 00 00 45 03 03 31 32 33 34 35 36 37 38 39   I...-..123456789
    

    After that, you'll have to fix the Cipher Suites Length field, which is currently set to 8192 (0x2000) and is also bogus. At most it's 32 (0x0020), so you could try changing this:

    0050   61 73 64 66 67 68 6a 00 20 00 cc a8 cc a9 c0 2f   asdfghj. ....../
    

    to this:

    0050   61 73 64 66 67 68 6a 00 00 20 cc a8 cc a9 c0 2f   asdfghj. ....../
    

    This should get you closer but you'll have to continue tweaking the data from there. And for anyone looking to test this, you can save the following data to a text file and then use text2pcap to convert it to a pcap file that Wireshark can load:

    0000   02 00 00 00 45 00 00 76 74 c5 40 00 80 06 00 00   ....E..vt.@.....
    0010   7f 00 00 01 7f 00 00 01 d9 2f 01 bb 7f 69 9a d9   ........./...i..
    0020   99 2a 47 85 50 18 27 f9 03 da 00 00 16 03 01 00   .*G.P.'.........
    0030   49 01 00 00 45 03 03 31 32 33 34 35 36 37 38 39   I...-..123456789
    0040   61 73 64 66 67 68 6a 6b 6c 7a 78 63 76 62 6e 6d   asdfghjklzxcvbnm
    0050   61 73 64 66 67 68 6a 00 00 20 cc a8 cc a9 c0 2f   asdfghj. ....../
    0060   c0 30 c0 2b c0 2c c0 13 c0 09 c0 14 c0 0a 00 9c   .0.+.,..........
    0070   00 9d 00 2f 00 35 c0 12 00 0a                     .../.5....
    

    Run text2pcap as follows:

    text2pcap.exe -l0 file.txt file.pcap