HackBlue

Tools · Wireshark · 20 / 30

A TLS handshake, and what stays hidden

The handshake shows who tried to talk and which parameters they chose. Application data stays unreadable without the client’s secrets.

14 min read · practice only with authorization

What you can read with no keys

A TLS session still has a visible start. Filter tls.handshake.type == 1 for Client Hello and tls.handshake.type == 2 for Server Hello. The client hello carries the server name in tls.handshake.extensions_server_name, the cipher suites on offer, and the versions the client is willing to speak. The server hello carries the suite and version that were chosen.

The record version on the outside of an early TLS 1.3 handshake often says TLS 1.2. The decision is in the supported_versions extension and the server hello, not in that outer number. Quote the field you actually read. Application data is tls.record.content_type == 23, and those bytes are ciphertext.

Snippet
tls.handshake.type == 1 && ip.addr == 10.8.0.40

The certificate is visible in TLS 1.2, and usually not in TLS 1.3

In a TLS 1.2 handshake the certificate message, tls.handshake.type == 11, shows the subject, the subject alternative names, and the validity dates. You can say which certificate the server presented. In TLS 1.3 that certificate is encrypted after the server hello. If the field is absent, the version may explain it. Absence is not a missing certificate on the server.

Encrypted Client Hello, when the client uses it, hides the server name that older handshakes left in the clear. If the extension is present and the server name field is empty, write that down. Do not treat a missing SNI as a broken capture until you have looked for that extension.

Keys you were given, and keys that will not help

A browser you own in the lab can write a key log, often via the SSLKEYLOGFILE environment variable. Point Wireshark’s TLS protocol preference at that file, then reopen the capture. Sessions from that client can be decrypted. Follow TLS Stream then shows the application data, including a cleartext HTTP request if the application sent one. The key log is a secret. Store it with the capture, not in a ticket.

The server’s certificate is not a decryption key. Modern suites use an ephemeral exchange, so the server private key does not open a recorded TLS 1.3 session, and it does not open a TLS 1.2 session that negotiated an ephemeral suite. If you were not given a key log or a matching secret, the honest result is the handshake metadata and nothing from inside the records.

Worked case: the name was visible, the path was not

10.8.0.40 opens TCP/443 to 203.0.113.50. Frame 300 is a Client Hello. The server name is files.example.test. Frame 301 is the Server Hello, and the chosen version is TLS 1.3. There is no certificate field to expand. The rest of the stream is application data. You can report the address, the port, the server name, the version, and the timing. You cannot report the URL path or a cookie.

A second capture, taken with a key log from the same lab browser, decrypts stream 4. The inner request is a GET /health. That path is evidence only because the key was supplied for a client you own. You note “decrypted with the lab key log” so nobody thinks the path was visible in the first file.

  • Visible: addresses, ports, SNI unless encrypted, chosen version and suite, timing, sizes.
  • Visible in TLS 1.2: the certificate message.
  • Hidden in the records: path, headers, cookies, body.
  • A key log from a client you own opens that client’s sessions.

Diagram

The handshake you can read, and the records you cannot

  1. Client Hello

    Read the server name, the offered versions, and the address.

    Client Hellos
    tls.handshake.type == 1
  2. Server Hello

    Read the chosen version and suite. Ignore the outer record version until you have checked supported_versions.

  3. Certificate

    Expand it when the version leaves it visible. TLS 1.3 usually encrypts it.

  4. Records

    Application data stays opaque without a key log from a client you own.

What the two files let you say

No key logLab key log loaded

stream 4 · TLS 1.3 · no key

Client Hello
server_name: files.example.test
to 203.0.113.50:443
Server Hello
TLS 1.3
then application data
  • You can quote the server name, the version, the address, and the time.
  • The certificate is not in the clear in this TLS 1.3 handshake.
  • The path and the cookies are inside the records.

same capture · lab key log

GET /health HTTP/1.1
Host: files.example.test
HTTP/1.1 200 OK
the body follows
  • The path is visible because the lab browser wrote a key log.
  • Say that in the note. The first file did not contain the path in the clear.
  • Keep the key log with the capture, out of the ticket.

Check yourself

1. Which field carries the hostname a client put in a clear Client Hello?

2. A TLS 1.3 handshake has no certificate message in the details tree. What is a sound reading?

3. You need the HTTP path inside a TLS session from a lab browser you own. What makes it readable?