As a leader in a SOC at a Managed Security Services Provider (MSSP), leading multiple teams, it is always interesting to see how new Analysts may freeze when they hear the communication is encrypted. What many of these new Analysts do not know, is in some cases, you may be able to decrypt this communication.
This post provides guidance to these new Analyst, to reduce their fear about being able to decrypt Transport Layer Security (TLS). Do keep in mind, while some of the TLS communication can be decrypted, there are many organizations which do not decrypt it.
As a result, let's take the opportunity to learn about TLS (some people still say SSL), starting with 1.0 before we even transition to the latest version (at the time of this writing) 1.3. A little theory is needed, before attempting to decrypt this communication.
Before going further, let's understand why we might or might not want encryption.
Here is a client and server session using ncat.
┌──(kali㉿securitynik)-[~] └─$ sudo ncat --verbose --listen 127.0.0.1 80 --nodns Ncat: Version 7.94 ( https://nmap.org/ncat ) Ncat: Listening on 127.0.0.1:80 Ncat: Connection from 127.0.0.1:55006. peek-a-boo, I can see you! Ooops, maybe we should encrypt this session! ----------------- ┌──(kali㉿securitynik)-[~] └─$ ncat --verbose 127.0.0.1 80 Ncat: Version 7.94 ( https://nmap.org/ncat ) Ncat: Connected to 127.0.0.1:80. peek-a-boo, I can see you! Ooops, maybe we should encrypt this session!
And here is the tcpdump output of that session.
┌──(kali㉿securitynik)-[~] └─$ sudo tcpdump -nnti lo port 80 -A 2>/dev/null IP 127.0.0.1.55006 > 127.0.0.1.80: Flags [P.], seq 3979765296:3979765323, ack 2665935488, win 512, options [nop,nop,TS val 3445312889 ecr 3445288637], length 27: HTTP E..O.S@.@..S...........P.6f0.........C..... .[My.Z..peek-a-boo, I can see you! IP 127.0.0.1.80 > 127.0.0.1.55006: Flags [.], ack 27, win 512, options [nop,nop,TS val 3445312889 ecr 3445312889], length 0 E..4`_@.@..b.........P.......6fK.....(..... .[My.[My IP 127.0.0.1.80 > 127.0.0.1.55006: Flags [P.], seq 1:46, ack 27, win 512, options [nop,nop,TS val 3445324807 ecr 3445312889], length 45: HTTP E..a``@.@..4.........P.......6fK.....U..... .[|..[MyOoops, maybe we should encrypt this session! IP 127.0.0.1.55006 > 127.0.0.1.80: Flags [.], ack 46, win 512, options [nop,nop,TS val 3445324807 ecr 3445324807], length 0 E..4.T@.@..m...........P.6fK.........(..... .[|..[|.
From monitoring of our enterprises, obviously, the more visibility we have the better we should be able to monitor. However, that visibility comes at a cost and makes it easier for threat actors to sniff traffic when on our networks and can exfiltrate data this way also.
Let's encrypt this communication. Here is the new ncat sessions.
┌──(kali㉿securitynik)-[~] └─$ sudo ncat --verbose --listen 127.0.0.1 80 --nodns --ssl Ncat: Version 7.94 ( https://nmap.org/ncat ) Ncat: Generating a temporary 2048-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one. Ncat: SHA-1 fingerprint: 8119 9A0B E2D0 4859 3357 56A2 A873 A544 9BB5 C9BC Ncat: Listening on 127.0.0.1:80 Ncat: Connection from 127.0.0.1:59900. Bet you can't see me now :-) I can see you but the sniffer can't :-D ----------------- ┌──(kali㉿securitynik)-[~] └─$ ncat --verbose 127.0.0.1 80 --ssl Ncat: Version 7.94 ( https://nmap.org/ncat ) Ncat: Subject: CN=127.0.0.1 Ncat: Issuer: CN=127.0.0.1 Ncat: SHA-1 fingerprint: 8119 9A0B E2D0 4859 3357 56A2 A873 A544 9BB5 C9BC Ncat: Certificate verification failed (self-signed certificate). Ncat: SSL connection to 127.0.0.1:80. Ncat: SHA-1 fingerprint: 8119 9A0B E2D0 4859 3357 56A2 A873 A544 9BB5 C9BC Bet you can't see me now :-) I can see you but the sniffer can't :-D
What does tcpdump see this time around?! Well, we can see the amount of bytes sent but not the actual contents, as seen in the unencrypted connections.
┌──(kali㉿securitynik)-[~] └─$ sudo tcpdump -nnti lo port 80 -v -A 2>/dev/null IP (tos 0x0, ttl 64, id 56647, offset 0, flags [DF], proto TCP (6), length 103) 127.0.0.1.59900 > 127.0.0.1.80: Flags [P.], cksum 0xfe5b (incorrect -> 0xdb9b), seq 2290212426:2290212477, ack 2645254601, win 512, options [nop,nop,TS val 3446108841 ecr 3446083161], length 51: HTTP E..g.G@.@._G...........P...J..a......[..... .gr..g.Y........,.?.(..'...dQ..?VF$.v..`x.h....`]K...)(y.u. IP (tos 0x0, ttl 64, id 31739, offset 0, flags [DF], proto TCP (6), length 52) 127.0.0.1.80 > 127.0.0.1.59900: Flags [.], cksum 0xfe28 (incorrect -> 0xa5ae), ack 51, win 512, options [nop,nop,TS val 3446108882 ecr 3446108841], length 0 E..4{.@.@............P....a....}.....(..... .gr..gr. IP (tos 0x0, ttl 64, id 31740, offset 0, flags [DF], proto TCP (6), length 114) 127.0.0.1.80 > 127.0.0.1.59900: Flags [P.], cksum 0xfe66 (incorrect -> 0x7609), seq 1:63, ack 51, win 512, options [nop,nop,TS val 3446132201 ecr 3446108841], length 62: HTTP E..r{.@.@............P....a....}.....f..... .g...gr.....9..../.H3..T..Bvs...,.>.....Jt....r .k..........@.y......U IP (tos 0x0, ttl 64, id 56648, offset 0, flags [DF], proto TCP (6), length 52) 127.0.0.1.59900 > 127.0.0.1.80: Flags [.], cksum 0xfe28 (incorrect -> 0xef18), ack 63, win 512, options [nop,nop,TS val 3446132201 ecr 3446132201], length 0 E..4.H@.@._y...........P...}..b......(..... .g...g..
Understanding TLS
TLS is responsible for providing authentication, encryption and integrity.
Authentication:
This is where each party verifies who the other claim to be.
In many cases, you are going to find the client verifying (authenticating) the server.
You can also have mutual authentication, where the server also verifies (authenticates) the client.
Encryption:
This is where the data is encrypted as it flows on the wire.
for example, let's say we had a file with the contents www.securitynik.com.
$ echo "www.securitynik.com" > test.txt $ cat test.txt www.securitynik.com
Now we want to encrypt this content.
$ openssl enc -aes-256-cbc -in test.txt -out test.enc -pbkdf2 -k test -p -e salt=03A2D1E4F026FCA5 key=4D4D864736E375BCF798E9BC871B0B372246C404490CB6ED30198B808A163093 iv =53DF5134171F4A028D0A8896F156E934
$ cat test.enc Salted__����&����g���`x��B{e� l�)k�����
Obviously, at this point there is not much we can make of the encrypted content. At this point, even if the communication channel is unencrypted, we can still pass this file on the wire without anyone being able to read the original content easily.
$ sudo ncat --verbose --listen 127.0.0.1 80 Ncat: Version 7.94 ( https://nmap.org/ncat ) Ncat: Listening on 127.0.0.1:80 Ncat: Connection from 127.0.0.1:47172. Salted__����&����g���`x��B{e� l�)k����� $ ncat --verbose 127.0.0.1 80 < test.enc Ncat: Version 7.94 ( https://nmap.org/ncat ) Ncat: Connected to 127.0.0.1:80. Ncat: 48 bytes sent, 1 bytes received in 0.10 seconds.
$ sudo tcpdump -nnti lo port 80 -A 2>/dev/null IP 127.0.0.1.47172 > 127.0.0.1.80: Flags [S], seq 767404127, win 65495, options [mss 65495,sackOK,TS val 1324986826 ecr 0,nop,wscale 7], length 0 E..<6=@.@..}.........D.P-.._.........0......... N........... IP 127.0.0.1.80 > 127.0.0.1.47172: Flags [S.], seq 3419229509, ack 767404128, win 65483, options [mss 65495,sackOK,TS val 1324986826 ecr 1324986826,nop,wscale 7], length 0 E..<..@.@.<..........P.D..ME-..`.....0......... N...N....... IP 127.0.0.1.47172 > 127.0.0.1.80: Flags [.], ack 1, win 512, options [nop,nop,TS val 1324986827 ecr 1324986826], length 0 E..46>@.@............D.P-..`..MF.....(..... N...N... IP 127.0.0.1.47172 > 127.0.0.1.80: Flags [P.], seq 1:49, ack 1, win 512, options [nop,nop,TS val 1324986827 ecr 1324986826], length 48: HTTP E..d6?@.@..S.........D.P-..`..MF.....X..... N...N...Salted__.....&....g....`x...B.{.e. l.)k.........
$ openssl enc -aes-256-cbc -in test.enc -out test.dec -pbkdf2 -k test -p -d $ cat test.dec www.securitynik.com
Integrity:
Validation that the data is not lost, damaged, tampered or falsified in any way.
Normally, when we talk about integrity, we are looking at it from simply the hashing function such as MD5, SHA-*, etc.
Let's hash the string "www.securitynik.com"
$ echo -n "www.securitynik.com" | openssl dgst -sha1 SHA1(stdin)= bc95e341c9912b5e5a257d35de91f8f6d7a84b7a
Now if a threat actor is able to see the string, it can be modified and the hash updated. This way, when the recipient receives the packet and compute the hash, it will match what the threat actor wanted. To mitigate this, Keyed-Hashing for Message Authentication is used via HMAC. With HMAC, along with the hash, we use a password/key.
$ echo -n "www.securitynik.com" | openssl dgst -sha1 -hmac "myKey" SHA1(stdin)= 0d109a1ce168f55d38bf4e0066cc6352fcd27815
TLS consists of a Record and a Handshake Protocol. These are also called layers. The Record Protocol provides security and reliability. Security is handled via symmetric cryptography (DES, AES, RC4, etc.) for data encryption. Reliability/Message integrity, is handled via hashing algorithm such as SHA, MD5, etc. The Record protocol may also be used without encryption. When a new connection begins, the Record layer connection, hash and compression states are all set to null.
Data fragmentation/reassembly into manageable blocks, optional compression/decompression, application of MAC and encryption/decryption prior to or after transmission is all done by the Record Protocol.
The Handshake protocol allow the server and client to authenticate each other, negotiate the encryption algorithm and cryptographic keys before any data is transmitted or received.
While the Record Protocol uses symmetric algorithms for encryption, the Handshake Protocol uses asymmetric (Public Key Cryptography: RSA, DSS, etc.). Authentication can be made optional but is generally required.
Once the channel is encrypted, the data sent by the two endpoints, is only visible by those two endpoints. The TLS protocol does not hide the length of the traffic of the data being transmitted. Do keep in mind that the TLS endpoints may pad the length to reduce the effectiveness of traffic analysis techniques.
To get an understanding of the TLS communications for both TLSv1.0 and TLSv1.3, we will target my domain: www.securitynik.com. If you are wondering why not TLSv1.2 also, well that falls within 1.0 and 1.3. My expectation is if you understand 1.0 and 1.3, then you have a good understanding of what is in the middle.
┌──(kali㉿securitynik)-[~] └─$ sslscan www.securitynik.com | grep --perl-regexp "Subject|Altnames|(TLSv1.0|TLSv1.3)\s+enabled" Subject: www.securitynik.com Altnames: DNS:www.securitynik.com
Interestingly, above does not show information about the versions of TLS enabled. I lost interest in trying to refine it :-D . Let's get this information another way. Copy and paste the output into a text editor such as vi, so you can see the actual output I am interested in.
┌──(kali㉿securitynik)-[~] └─$ cat /tmp/ssl.txt | grep --perl-regexp "Subject|Altnames|(TLSv1.0|TLSv1.3)\s+enabled" TLSv1.0 enabled TLSv1.3 enabled Subject: www.securitynik.com Altnames: DNS:www.securitynik.com
TLSv1.0
Was launched in January 1999 via RFC 2246.
┌──(kali㉿securitynik)-[~] └─$ sudo tcpdump -n -w securitynik_tls1.0.pcap 'tcp port 443 and host www.securitynik.com' -v tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes Got 338 ^C338 packets captured 344 packets received by filter 0 packets dropped by kernel
┌──(kali㉿securitynik)-[~] └─$ curl --verbose https://www.securitynik.com --tlsv1.0 --tls-max 1.0 | more % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 142.251.32.83:443... * Connected to www.securitynik.com (142.251.32.83) port 443 (#0) * ALPN: offers h2,http/1.1 } [5 bytes data] * TLSv1.0 (OUT), TLS handshake, Client hello (1): } [177 bytes data] * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs { [5 bytes data] * TLSv1.0 (IN), TLS handshake, Server hello (2): { [100 bytes data] * TLSv1.0 (IN), TLS handshake, Certificate (11): { [4212 bytes data] * TLSv1.0 (IN), TLS handshake, Server key exchange (12): { [298 bytes data] * TLSv1.0 (IN), TLS handshake, Server finished (14): { [4 bytes data] * TLSv1.0 (OUT), TLS handshake, Client key exchange (16): } [37 bytes data] * TLSv1.0 (OUT), TLS change cipher, Change cipher spec (1): } [1 bytes data] * TLSv1.0 (OUT), TLS handshake, Finished (20): } [16 bytes data] * TLSv1.0 (IN), TLS handshake, Finished (20): { [16 bytes data] * SSL connection using TLSv1 / ECDHE-RSA-AES128-SHA * ALPN: server accepted h2 * Server certificate: * subject: CN=www.securitynik.com * start date: May 30 04:44:46 2023 GMT * expire date: Aug 28 05:31:35 2023 GMT * subjectAltName: host "www.securitynik.com" matched cert's "www.securitynik.com" * issuer: C=US; O=Google Trust Services LLC; CN=GTS CA 1D4 * SSL certificate verify ok. } [5 bytes data] * using HTTP/2 ......
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.0.pcap -c 3 1 0.000000 10.0.1.128 → 142.251.32.83 TCP 74 41570 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM TSval=971727410 TSecr=0 WS=128 2 0.014645 142.251.32.83 → 10.0.1.128 TCP 60 443 → 41570 [SYN, ACK] Seq=0 Ack=1 Win=64240 Len=0 MSS=1460 3 0.014733 10.0.1.128 → 142.251.32.83 TCP 54 41570 → 443 [ACK] Seq=1 Ack=1 Win=64240 Len=0
4 0.019859 10.0.1.128 → 142.251.32.83 TLSv1 236 Client Hello
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.0.pcap -Y "tls.handshake.type == 1" -V | sed '1,81d;128,$d' Transport Layer Security TLSv1 Record Layer: Handshake Protocol: Client Hello 1: Content Type: Handshake (22) 2: Version: TLS 1.0 (0x0301) 3: Length: 177 Handshake Protocol: Client Hello 4: Handshake Type: Client Hello (1) 5: Length: 173 6: Version: TLS 1.0 (0x0301) Random: d21450dca6d7d0a53270853149ffa3bd2e6004eecaa7a50666386b6ccc26c817 7: GMT Unix Time: Sep 8, 2081 04:46:20.000000000 EDT 8: Random Bytes: a6d7d0a53270853149ffa3bd2e6004eecaa7a50666386b6ccc26c817 9: Session ID Length: 0 10: Cipher Suites Length: 54 11: Cipher Suites (27 suites) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014) Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039) Cipher Suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA (0x0038) Cipher Suite: TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (0x0088) Cipher Suite: TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA (0x0087) Cipher Suite: TLS_ECDH_anon_WITH_AES_256_CBC_SHA (0xc019) Cipher Suite: TLS_DH_anon_WITH_AES_256_CBC_SHA (0x003a) Cipher Suite: TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA (0x0089) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033) Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA (0x0032) Cipher Suite: TLS_DHE_RSA_WITH_SEED_CBC_SHA (0x009a) Cipher Suite: TLS_DHE_DSS_WITH_SEED_CBC_SHA (0x0099) Cipher Suite: TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (0x0045) Cipher Suite: TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA (0x0044) Cipher Suite: TLS_ECDH_anon_WITH_AES_128_CBC_SHA (0xc018) Cipher Suite: TLS_DH_anon_WITH_AES_128_CBC_SHA (0x0034) Cipher Suite: TLS_DH_anon_WITH_SEED_CBC_SHA (0x009b) Cipher Suite: TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA (0x0046) Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035) Cipher Suite: TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (0x0084) Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) Cipher Suite: TLS_RSA_WITH_SEED_CBC_SHA (0x0096) Cipher Suite: TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (0x0041) Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff) 12: Compression Methods Length: 1 13: Compression Methods (1 method) 14: Compression Method: null (0) 15: Extensions Length: 78
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.0.pcap -Y "tls.handshake.type == 2" -V | sed '1,82d;100,$d' Transport Layer Security TLSv1 Record Layer: Handshake Protocol: Server Hello 1: Content Type: Handshake(22) 2: Version: TLS 1.0 (0x0301) Length: 100 Handshake Protocol: Server Hello 3: Handshake Type: Server Hello (2) Length: 96 4: Version: TLS 1.0 (0x0301) Random: 64b57bddd6dd95316e80d2d04a66ffcebb3f853e885b61d4444f574e47524400 5: GMT Unix Time: Jul 17, 2023 13:35:25.000000000 EDT 6: Random Bytes: d6dd95316e80d2d04a66ffcebb3f853e885b61d4444f574e47524400 7: Session ID Length: 32 8: Session ID: f943d4e522980ff86ab6371b4bd77e9dbe71cf3dbd939c54d17c08c6710a783d 9: Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) 10: Compression Method: null (0) 11: Extensions Length: 24
The server responds to a "Client Hello" with a "Server Hello", assuming that that it finds an acceptable set of algorithm.
We've discussed 1, 2 and 3 as it relates to the Client Hello. No need to repeat here.
Starting from bullet 4.
4: Handshake Type: We see handshake type 2 which is the Server Hello.
5: GMT Unix Time: This represents the current time and date in seconds, since January 1, 1970 according to the client's internal clock. Unlike the Client Hello, we do see the true date and time when this negotiation was started from the Server Hello perspective.
6: Random Bytes: Generated by the server and must be different and independent from the Client.Hello.random, whichis part of the Client Hello.
7: Session ID Length: These 32 bytes represents the value of the session ID.
8: Session ID: If this was an attempt to reuse an existing ID and the server is willing to establish the connection, then the "Session ID" sent via the Client Hello would be reused here. However, above, we saw the Client Hello had a Session ID of 0. As a result, the value in this field represents a new Session ID. It is also possible for the server to respond with an empty Session ID, meaning this session will not be cached and thus cannot be resumed.
9: Cipher Suite: Where as the Client Hello had 27 cipher suites above, the server hello will have one. This is the one selected from the client's list chosen by the server. If the session was resumed, this will be the value from the resumed session. The choice made in this case is TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
10: Compression Method: null (0). No compression is being used here.
11: Extensions Length: 24. While there are 24 extensions, like the Client Hello extensions, we are not going to cover those.
Looking at handshake type 11 - Server Certificate.
Transport Layer Security TLSv1 Record Layer: Handshake Protocol: Certificate Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 4212 Handshake Protocol: Certificate Handshake Type: Certificate (11) Length: 4208 Certificates Length: 4205 Certificates (4205 bytes) Certificate Length: 1390 Certificate: 3082056a30820452a003020102021061e289d6689c9871120ac9bfb26a5e67300d06092a… (id-at-commonName=www.securitynik.com) signedCertificate version: v3 (2) serialNumber: 0x61e289d6689c9871120ac9bfb26a5e67 signature (sha256WithRSAEncryption) .... Certificate Length: 1424 Certificate: 3082058c30820374a003020102020d02008eb2023336658b64cddb9b300d06092a864886… (id-at-commonName=GTS CA 1D4,id-at-organizationName=Google Trust Services LLC,id-at-countryName=US) signedCertificate version: v3 (2) serialNumber: 0x02008eb2023336658b64cddb9b signature (sha256WithRSAEncryption) .... Certificate Length: 1382 Certificate: 308205623082044aa003020102021077bd0d6cdb36f91aea210fc4f058d30d300d06092a… (id-at-commonName=GTS Root R1,id-at-organizationName=Google Trust Services LLC,id-at-countryName=US) signedCertificate version: v3 (2) serialNumber: 0x77bd0d6cdb36f91aea210fc4f058d30d signature (sha256WithRSAEncryption) ....
Transport Layer Security TLSv1 Record Layer: Handshake Protocol: Server Key Exchange Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 298 Handshake Protocol: Server Key Exchange Handshake Type: Server Key Exchange (12) Length: 294 1: EC Diffie-Hellman Server Params Curve Type: named_curve (0x03) Named Curve: x25519 (0x001d) Pubkey Length: 32 Pubkey: 0aa2761ebf46891226b8005989b2ff16031eb992071eeb39fabc67c84804fc1d Signature Length: 256 Signature: 7a962b3224cbd01508d562d92f8c328c5b2c813b6d2361934d6742fb2eba6e4dc6db02e6…
The Server Key Exchange message is sent directly after the server sends its certificate message and is used by the client to communicate the premaster secret. It is sent by the server only when the server certificate does not contain enough data to allow the client to exchange a premaster secret. So while our server certificate above uses RSA for authentication, we can see the Server Key Exchange message is instead using "EC Diffie-Hellman Server Params". One of the reasons for using the Server Key Exchange message is if the RSA_EXPORT public key is longer than 512 bits. I know the server certificate is using RSA but I did not notice anything specific for RSA_EXPORT. Anyhow, the public key for this cert is 2048 bits. Hence longer than 512 bits.
The client may use an RSA public key to encrypt the premaster secret or a Diffile-Hellman Public Key to complete the key exchange ("with the result being the premaster secret")
Closing out, we see the Server Hello process completed, with the "Server Hello Done" message. This message is sent to state that the server is done sending messages to support the key exchange. The client can now proceed with its phase of the key exchange process. The server now waits for the client's response.
TLSv1 Record Layer: Handshake Protocol: Server Hello Done Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 4 Handshake Protocol: Server Hello Done 1: Handshake Type: Server Hello Done (14) Length: 0
Looking at the Client Key Exchange message
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.0.pcap -Y "tls.handshake.type == 16" -V | sed '1,81d' Transport Layer Security TLSv1 Record Layer: Handshake Protocol: Client Key Exchange Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 37 Handshake Protocol: Client Key Exchange Handshake Type: Client Key Exchange (16) Length: 33 EC Diffie-Hellman Client Params Pubkey Length: 32 Pubkey: ccdcc7ebb6ce8463f664c562cffd616daeaf23690777570e3a333168473b082d
TLSv1 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec Content Type: Change Cipher Spec (20) Version: TLS 1.0 (0x0301) Length: 1 Change Cipher Spec Message
After the Change Cipher Spec, a finished message is sent. This verifies that the key exchange and authentication process were successful. This is the first protected message which uses the negotiated algorithms, keys and secrets. Once a peer has sent its Finished message and received and validated the Finished message from its peer, it may then begin to send and receive data over this connection.
TLSv1 Record Layer: Handshake Protocol: Encrypted Handshake Message Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 48 Handshake Protocol: Encrypted Handshake Message
Wrapping this up by looking at the server's Change Cipher Spec and Finished messages.
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.0.pcap -Y "(tls.record.content_type == 20) && (tcp.srcport == 443)" -V | sed '1,81d' Transport Layer Security TLSv1 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec Content Type: Change Cipher Spec (20) Version: TLS 1.0 (0x0301) Length: 1 Change Cipher Spec Message TLSv1 Record Layer: Handshake Protocol: Encrypted Handshake Message Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 48 Handshake Protocol: Encrypted Handshake Message
Finally, we see the application data is encrypted. Note, while the data is encrypted, we are still able to see that the protocol being encrypted is HTTP2.
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.0.pcap -Y "((tls.record.content_type == 23) && (tls.record.length == 64)) && (tcp.srcport == 443)" -V | sed '1,81d' Transport Layer Security TLSv1 Record Layer: Application Data Protocol: HyperText Transfer Protocol 2 Content Type: Application Data (23) Version: TLS 1.0 (0x0301) Length: 64 Encrypted Application Data: b35dacf71de0fa03a23a0bdea81200463de633f3efe3985b99ba80c38e0d901addba430a… [Application Data Protocol: HyperText Transfer Protocol 2]
Here is that full sequence of packets.
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.0.pcap -c 15 1 0.000000 10.0.1.128 → 142.251.32.83 TCP 74 41570 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM TSval=971727410 TSecr=0 WS=128 2 0.014645 142.251.32.83 → 10.0.1.128 TCP 60 443 → 41570 [SYN, ACK] Seq=0 Ack=1 Win=64240 Len=0 MSS=1460 3 0.014733 10.0.1.128 → 142.251.32.83 TCP 54 41570 → 443 [ACK] Seq=1 Ack=1 Win=64240 Len=0 4 0.019859 10.0.1.128 → 142.251.32.83 TLSv1 236 Client Hello 5 0.020277 142.251.32.83 → 10.0.1.128 TCP 60 443 → 41570 [ACK] Seq=1 Ack=183 Win=64240 Len=0 6 0.069372 142.251.32.83 → 10.0.1.128 TLSv1 1466 Server Hello 7 0.069395 10.0.1.128 → 142.251.32.83 TCP 54 41570 → 443 [ACK] Seq=183 Ack=1413 Win=63540 Len=0 8 0.069978 142.251.32.83 → 10.0.1.128 TCP 2878 443 → 41570 [PSH, ACK] Seq=1413 Ack=183 Win=64240 Len=2824 [TCP segment of a reassembled PDU] 9 0.069993 10.0.1.128 → 142.251.32.83 TCP 54 41570 → 443 [ACK] Seq=183 Ack=4237 Win=61320 Len=0 10 0.070291 142.251.32.83 → 10.0.1.128 TLSv1 452 Certificate, Server Key Exchange, Server Hello Done 11 0.070300 10.0.1.128 → 142.251.32.83 TCP 54 41570 → 443 [ACK] Seq=183 Ack=4635 Win=61320 Len=0 12 0.082053 10.0.1.128 → 142.251.32.83 TLSv1 155 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message 13 0.082396 142.251.32.83 → 10.0.1.128 TCP 60 443 → 41570 [ACK] Seq=4635 Ack=284 Win=64240 Len=0 14 0.122781 142.251.32.83 → 10.0.1.128 TLSv1 113 Change Cipher Spec, Encrypted Handshake Message 15 0.122974 142.251.32.83 → 10.0.1.128 TLSv1 123 Application Data
TLS 1.3
┌──(kali㉿securitynik)-[~] └─$ sudo tcpdump -n -w securitynik_tls1.3.pcap 'tcp port 443 and host www.securitynik.com' -v tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes q^C142 packets captured 148 packets received by filter 0 packets dropped by kernel
┌──(kali㉿securitynik)-[~] └─$ curl --verbose https://www.securitynik.com --tlsv1.3 --tls-max 1.3 | more % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 142.251.32.83:443... * Connected to www.securitynik.com (142.251.32.83) port 443 (#0) * ALPN: offers h2,http/1.1 } [5 bytes data] * TLSv1.3 (OUT), TLS handshake, Client hello (1): } [512 bytes data] * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs { [5 bytes data] * TLSv1.3 (IN), TLS handshake, Server hello (2): { [122 bytes data] * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): { [15 bytes data] * TLSv1.3 (IN), TLS handshake, Certificate (11): { [4219 bytes data] * TLSv1.3 (IN), TLS handshake, CERT verify (15): { [264 bytes data] * TLSv1.3 (IN), TLS handshake, Finished (20): { [52 bytes data] * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): } [1 bytes data] * TLSv1.3 (OUT), TLS handshake, Finished (20): } [52 bytes data] * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN: server accepted h2 * Server certificate: * subject: CN=www.securitynik.com * start date: May 30 04:44:46 2023 GMT * expire date: Aug 28 05:31:35 2023 GMT * subjectAltName: host "www.securitynik.com" matched cert's "www.securitynik.com" * issuer: C=US; O=Google Trust Services LLC; CN=GTS CA 1D4 * SSL certificate verify ok. } [5 bytes data] * using HTTP/2
As we dig into TLS 1.3, we will not review every field but will try to identify the difference between TLS 1.0 while learning about 1.3. We already know the 3-way handshake has to be completed, so no need for us to repeat that step.
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.3.pcap -Y "tls.handshake.type == 1" -V | sed '1,81d;221,$d' Transport Layer Security TLSv1 Record Layer: Handshake Protocol: Client Hello Content Type: Handshake (22) 1: Version: TLS 1.0 (0x0301) Length: 512 Handshake Protocol: Client Hello Handshake Type: Client Hello (1) Length: 508 2: Version: TLS 1.2 (0x0303) Random: 7c818caebba31899f0cfa4b428d9cb77472cc14adcc6754f112154a448ce789f GMT Unix Time: Mar 11, 2036 12:15:42.000000000 EDT 3: Random Bytes: bba31899f0cfa4b428d9cb77472cc14adcc6754f112154a448ce789f Session ID Length: 32 4: Session ID: edb77086c25eb6bd211601cbbda8a316018082c8c67f02e9738e40226e2c4f30 Cipher Suites Length: 8 5: Cipher Suites (4 suites) Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302) Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303) Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301) Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff) 6: Compression Methods Length: 1 Compression Methods (1 method) Compression Method: null (0) 7: Extensions Length: 427 ... 8: Extension: supported_groups (len=22) Type: supported_groups (10) Length: 22 Supported Groups List Length: 20 Supported Groups (10 groups) Supported Group: x25519 (0x001d) Supported Group: secp256r1 (0x0017) Supported Group: x448 (0x001e) ... 9: Extension: signature_algorithms (len=30) Type: signature_algorithms (13) Length: 30 Signature Hash Algorithms Length: 28 Signature Hash Algorithms (14 algorithms) Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403) Signature Hash Algorithm Hash: SHA256 (4) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503) Signature Hash Algorithm Hash: SHA384 (5) Signature Hash Algorithm Signature: ECDSA (3) Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603) Signature Hash Algorithm Hash: SHA512 (6) Signature Hash Algorithm Signature: ECDSA (3) ... 10: Extension: supported_versions (len=3) Type: supported_versions (43) Length: 3 Supported Versions length: 2 Supported Version: TLS 1.3 (0x0304) Extension: psk_key_exchange_modes (len=2) Type: psk_key_exchange_modes (45) Length: 2 PSK Key Exchange Modes Length: 1 PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1) Extension: key_share (len=38) Type: key_share (51) Length: 38 Key Share extension Client Key Share Length: 36 Key Share Entry: Group: x25519, Key Exchange length: 32 Group: x25519 (29) Key Exchange Length: 32 Key Exchange: 7d0b7c312e2e88130463417583423ca34085069e2950c9d08bc737e96e12b757
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.3.pcap -Y "tls.handshake.type == 2" -V | sed '1,82d' Transport Layer Security TLSv1.2 Record Layer: Handshake Protocol: Server Hello Content Type: Handshake (22) Version: TLS 1.2 (0x0303) Length: 122 Handshake Protocol: Server Hello 1: Handshake Type: Server Hello (2) Length: 118 Version: TLS 1.2 (0x0303) Random: da42c2479a3a83e8d13b13b9fbf446953a5b301c93c16c0e47fb661212ac13f0 Session ID Length: 32 Session ID: edb77086c25eb6bd211601cbbda8a316018082c8c67f02e9738e40226e2c4f30 2: Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302) Compression Method: null (0) Extensions Length: 46 3: Extension: key_share (len=36) Type: key_share (51) Length: 36 Key Share extension Key Share Entry: Group: x25519, Key Exchange length: 32 Group: x25519 (29) Key Exchange Length: 32 Key Exchange: b890eba94dad2c2bd955684a395592e1d26ed73308d4d9eed988912afafc5a13 4: Extension: supported_versions (len=2) Type: supported_versions (43) Length: 2 Supported Version: TLS 1.3 (0x0304) [JA3S Fullstring: 771,4866,51-43] [JA3S: 907bf3ecef1c987c889946b737b43de8] 5: TLSv1.3 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec Content Type: Change Cipher Spec (20) Version: TLS 1.2 (0x0303) Length: 1 Change Cipher Spec Message
We already learned from the Client Hello that fields such as version, session_id, compression_method, etc., are deprecated. No need to touch on them again. Keeping it simple.
1: Handshake Type: Server Hello in response to the Client's Hello.
2. Cipher Suite: The value selected represents the chosen cipher suite from the Client's Hello message. As we see in this list, the server choose the first value. Considering the client already sent its key_share and the server has now chosen the algorithm, the server can then generate it's key_share which it will send to the client. At the same time, the server can use the client's key_share and its key_share to generate the symmetric key needed for encryption.
3. Key_share: The server calculates its Key_share value based on the first item in the client's list of supported_groups.
4. supported_versions, identify this as TLS 1.3.
5. The communication transition to encrypted. Not much for us to do beyond here. This is where however, the Server Certificate, etc., is sent for the client to authenticate the server.
Looking at frame 8, we see encrypted application data and the protocol being HTTP.
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.3.pcap -Y "frame.number == 8" -V | sed '1,89d' TLSv1.3 Record Layer: Application Data Protocol: Hypertext Transfer Protocol Opaque Type: Application Data (23) Version: TLS 1.2 (0x0303) Length: 4567 Encrypted Application Data: 9b533b25659e1404e41388747c1a403679bf9b986c3127f65f13a5a0a01fd03aa21b40c7… [Application Data Protocol: Hypertext Transfer Protocol]
┌──(kali㉿securitynik)-[~] └─$ tshark -n -r securitynik_tls1.3.pcap -Y "tls.handshake.type == 1" -V | sed '1,105d;114,$d' Extension: server_name (len=24) Type: server_name (0) Length: 24 Server Name Indication extension Server Name list length: 22 Server Name Type: host_name (0) Server Name length: 19 Server Name: www.securitynik.com
So as seen above, even without decrypting, we are able to see the domain the client is going to. This is exactly the feature that my tool pktItel.py (https://github.com/SecurityNik/pktIntel) uses.
Let's decrypt from a few perspectives.
First let's decrypt using the SSLKEYLOGFILE.
To decrypt from the browser or from a command line tool such as curl that supports SSL decryption, we need to set the SSLKEYLOGFILE environment variable. Let's do this!
┌──(kali㉿securitynik)-[~] └─$ export SSLKEYLOGFILE=/home/kali/sslkeylog.file ┌──(kali㉿securitynik)-[~] └─$ echo $SSLKEYLOGFILE /home/kali/sslkeylog.file ┌──(kali㉿securitynik)-[~] └─$ ls sslkeylogfile*.* ls: cannot access 'sslkeylogfile*.*': No such file or directory
First I create environment variable via the export command.
Next I validated the SSLKEYLOGFILE environment variable was created by using the echo command.
When the variable was created, it pointed to a file. When I ran ls, we see the file does not currently exists. If this was setup correctly, the file will be created automatically, once they (pre-)master secrets are written to it.
Setup TShark to capture the traffic.
┌──(kali㉿securitynik)-[~] └─$ sudo tshark --interface eth0 -w /tmp/curl.pcapng -f 'port 443 and host www.securitynik.com' Running as user "root" and group "root". This could be dangerous. Capturing on 'eth0' ** (tshark:151432) 13:57:39.885233 [Main MESSAGE] -- Capture started. ** (tshark:151432) 13:57:39.885309 [Main MESSAGE] -- File: "/tmp/curl.pcapng"
┌──(kali㉿securitynik)-[~] └─$ curl --silent https://www.securitynik.com --tlsv1.3 --tls-max 1.3 --output /tmp/index.txt
┌──(kali㉿securitynik)-[~] └─$ ls sslkeylog.file -l -rw-r--r-- 1 kali kali 938 Jul 24 14:00 sslkeylog.file
┌──(kali㉿securitynik)-[~] └─$ head sslkeylog.file SERVER_HANDSHAKE_TRAFFIC_SECRET edbe2472eead5da6a5c23a3eaca03e1b7d16a42bb9d29ea451bc8588c4bf7d15 81965dd5815a94c08b183d6967e92a9d425d579acc64e29fd381dbd9ba370db5070fc906d3ac46f4dd0c093620d06dac EXPORTER_SECRET edbe2472eead5da6a5c23a3eaca03e1b7d16a42bb9d29ea451bc8588c4bf7d15 7b36723ef808a75158ffc36e40c0928af50022585b7b436a5a017b79927d961daf06a237d8e683435d86539586136f42 SERVER_TRAFFIC_SECRET_0 edbe2472eead5da6a5c23a3eaca03e1b7d16a42bb9d29ea451bc8588c4bf7d15 17403da98e23b307d25b0d5f7e3987f53f9636b29b51042fdec9abe29ea2c717afb723a3c69b365b0682f636d6c13503 CLIENT_HANDSHAKE_TRAFFIC_SECRET edbe2472eead5da6a5c23a3eaca03e1b7d16a42bb9d29ea451bc8588c4bf7d15 c648aa60612a3437d113105bc22979ba6de182d0ab0b85e48403a59570e5a690c1fb502976993d5c145b888651f56cbc CLIENT_TRAFFIC_SECRET_0 edbe2472eead5da6a5c23a3eaca03e1b7d16a42bb9d29ea451bc8588c4bf7d15 56122f06fef5db1ba481b9bd282cd7ec00a8e5246f901d1ae5c650c9bbe1b15cfbb6777ca04392efa0a3ab890d01fbd9
What are those values? See the reference section. Basically those are the secrets used to encrypt the application data or the handshake, etc.
Note, because we set the SSLKEYLOGFILE environment variable, if we open our browser and it has been compiled with this option, then similarly the connections your browsers make, will result in information be written to this file. Hence, I am not going to repeat this with a browser. You can test it for yourself.
How do we decrypt this? Let's try to look at the protocol hierarchy of the undecrypted traffic with TShark.
┌──(kali㉿securitynik)-[~] └─$ sudo tshark -n -r /tmp/curl.pcapng -q -z io,phs 2>/dev/null =================================================================== Protocol Hierarchy Statistics Filter: eth frames:622 bytes:1095342 ip frames:622 bytes:1095342 tcp frames:622 bytes:1095342 tls frames:313 bytes:1078582 tcp.segments frames:121 bytes:504319 tls frames:101 bytes:496976 ===================================================================
┌──(kali㉿securitynik)-[~] └─$ sudo tshark -n -r /tmp/curl.pcapng -q -z io,phs -o "tls.keylog_file: /home/kali/sslkeylog.file" 2>/dev/null =================================================================== Protocol Hierarchy Statistics Filter: eth frames:622 bytes:1095342 ip frames:622 bytes:1095342 tcp frames:622 bytes:1095342 tls frames:313 bytes:1078582 http2 frames:52 bytes:227960 http2 frames:2 bytes:256 http2 frames:1 bytes:140 tls.segments frames:45 bytes:227055 tcp.segments frames:9 bytes:55662 tls frames:8 bytes:51372 http2 frames:2 bytes:17052 tls.segments frames:2 bytes:17052 http2 frames:1 bytes:6333 tls.segments frames:1 bytes:6333 tcp.segments frames:112 bytes:448657 tls frames:93 bytes:445604 http2 frames:28 bytes:239306 tls.segments frames:27 bytes:234102 http2 frames:4 bytes:51048 tls.segments frames:4 bytes:51048 data-text-lines frames:1 bytes:5204 tls.segments frames:1 bytes:5204 http2 frames:1 bytes:5204 ===================================================================
┌──(kali㉿securitynik)-[~] └─$ sudo tshark -n -r /tmp/curl.pcapng -o "tls.keylog_file: /home/kali/sslkeylog.file" -q -z follow,tls,ascii,0 | head --lines=30 Running as user "root" and group "root". This could be dangerous. =================================================================== Follow: tls,ascii Filter: tcp.stream eq 0 Node 0: 142.251.41.51:443 Node 1: :0 64 PRI * HTTP/2.0 SM ..............d......................... 43 ..".........A.....)-...Q..C.z.%.P.....S.*/* 40 ..............d......................... 9 ......... 9 ......... 191 .........._.I|...M.j.q........d..z...Je....2.^..\e.1h.....z...Je....2.^..\e.1h.X...w.K..#...,.l..m_J..2.B...P..e...LZ7.@....RKRVO....I.R?......@....!j.:JD........B...'_v.GSER....{...-i[.D<..o 1408 .1~......<!DOCTYPE html> <html class='v2' dir='ltr' lang='en' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'> <head> <link href='https://www.blogger.com/static/v1/widgets/3566091532-css_bundle_v2.css' rel='stylesheet' type='text/css'/> <!-- ADDED BY NIK --> <script async='async' src='//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js'></script> <script>
┌──(kali㉿securitynik)-[~] └─$ sudo tshark -n -r /tmp/curl.pcapng -o "tls.keylog_file: /home/kali/sslkeylog.file" -q -z follow,tls,ascii,0 | grep --perl-regexp --ignore-case "securitynik" --only-matching | sort | uniq --count Running as user "root" and group "root". This could be dangerous. 308 securitynik 29 SecurityNik
PS C:\Users\securitynik> tasklist | findstr /i msedge msedge.exe 7092 Console 1 98,560 K msedge.exe 7108 Console 1 7,336 K msedge.exe 4600 Console 1 29,444 K msedge.exe 5592 Console 1 32,508 K msedge.exe 2052 Console 1 18,900 K msedge.exe 7676 Console 1 104,520 K msedge.exe 7988 Console 1 27,212 K PS C:\Users\securitynik> Get-Process msedge | Select-Object -Property ProcessName ProcessName ----------- msedge msedge msedge msedge msedge msedge msedge
PS C:\Users\Administrator> taskkill /IM msedge.exe /F SUCCESS: The process "msedge.exe" with PID 7092 has been terminated. SUCCESS: The process "msedge.exe" with PID 7108 has been terminated. SUCCESS: The process "msedge.exe" with PID 4600 has been terminated. SUCCESS: The process "msedge.exe" with PID 5592 has been terminated. SUCCESS: The process "msedge.exe" with PID 2052 has been terminated. SUCCESS: The process "msedge.exe" with PID 7676 has been terminated. SUCCESS: The process "msedge.exe" with PID 7988 has been terminated.
PS C:\Users\Administrator> setx SSLKEYLOGFILE "$(get-location)\sslkeylog_file.txt" SUCCESS: Specified value was saved.
C:\Users\SecurityNik>set|findstr /i ssl SSLKEYLOGFILE=C:\Users\SecurityNik\sslkeylog_file.txt
PS C:\Users\Administrator> Invoke-WebRequest -uri https://www.securitynik.com -OutFile index.html
PS C:\Users\Administrator> dir ssl*.*
C:\Users\Administrator>dir ssl*.* /b sslkeylog_file.txt
┌──(kali㉿securitynik)-[~] └─$ ss --numeric --listening --tcp --processes State Recv-Q Send-Q Local Address:Port Peer Address:Port Process LISTEN 0 50 [::ffff:127.0.0.1]:8080 *:* users:(("java",pid=210127,fd=26))
HMAC-SHA1 in bash - Stack Overflow
How To Encrypt Files With OpenSSL (linuxwebdevelopment.com)
encryption - How to use OpenSSL to encrypt/decrypt files? - Stack Overflow
TLS Versions: What They Are and Which Ones Are Still Supported? (cheapsslsecurity.com)