Decrypt TLS in a PCAP with an SSLKEYLOGFILE
Decrypt TLS 1.2 and TLS 1.3 traffic in a capture using the key log the challenge gave you, entirely in the browser.
Open in ctfpalA capture full of TLS is not a dead end if the challenge also handed you a file of hex lines. That file is an SSLKEYLOGFILE: the secrets a browser or a client library writes out when told to, and enough to derive the record keys for the sessions it covers.
What a key log looks like
CLIENT_RANDOM 52362c...c9a1 9f8b7a...4d2e
CLIENT_HANDSHAKE_TRAFFIC_SECRET 52362c...c9a1 1a2b3c...
SERVER_HANDSHAKE_TRAFFIC_SECRET 52362c...c9a1 4d5e6f...
CLIENT_TRAFFIC_SECRET_0 52362c...c9a1 7a8b9c...
SERVER_TRAFFIC_SECRET_0 52362c...c9a1 0d1e2f...The client random is what pairs a secret with a session, which is why the same file can decrypt several connections at once and why a key log from a different run is useless: the randoms will not match anything in your capture.
What is supported, and what is not
- TLS 1.2 with AES-128-GCM, AES-256-GCM and ChaCha20-Poly1305, from a
CLIENT_RANDOMline. - TLS 1.3 from the handshake and application traffic secrets, with HKDF-Expand-Label key derivation.
- Not CBC-mode suites, not RSA key exchange from a server private key, and not sessions whose secrets are missing from the log.
Generating one yourself
If the challenge expects you to capture your own traffic, set SSLKEYLOGFILE=/path/to/keys.log in the environment before starting Firefox, Chrome, or anything built on curl or OpenSSL, and capture at the same time. Both files are needed and they have to be from the same run.
Common questions
- The capture has TLS but no key log. Can it still be decrypted?
- Not by anything here, and in general not at all. Any suite with forward secrecy - which is all of TLS 1.3 and nearly all of TLS 1.2 in practice - cannot be decrypted from a server private key after the fact. If a challenge involves TLS, it will give you either the key log or a way to obtain it; that is the challenge.
- It decrypted some sessions but not others.
- The key log covers whichever sessions were open while it was being written. A session whose client random has no matching line stays encrypted, and that is expected rather than an error.