Wednesday, August 9, 2023

Understanding and Decrypting TLS based communication - HTTP over TLS (HTTPS)

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..

With that out of the way, let's get to the theory ....


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


After encryption rather than www.securitynik.com, we see
$ 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. 

Below we setup ncat to listen for the incoming file on the server side and then the client uses the encrypted file as input.

$ 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.


When we look on the wire, there is a hint that this communication is encrypted but nothing much for us to interpret via cleartext.

$ 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.........


  Because we used symmetric encryption, we only need the same key/password to decrypt the file on the receiver side
  To decrypt, we rerun the command and add the "-d" option. We also change the input file to be the encrypted file while creating a new out file with the decrypted content.
$ openssl enc -aes-256-cbc -in test.enc -out test.dec -pbkdf2 -k test -p -d

$ cat test.dec 
www.securitynik.com

    Awesome, we recovered the file while getting a better understanding of symmetric encryption.

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.

Understanding TLSv1.0 through packet analysis. Let's setup tcpdump to capture the traffic of interest. Note below shows the captured traffic also.

┌──(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

Here is the curl command line to force curl to use TLSv1.0

┌──(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
......

Reviewing the PCAP file.

As TLS run above TCP (in this example), first, we see the TCP 3-way handshake

┌──(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

Next packet to come is the "Client Hello"

4   0.019859   10.0.1.128 → 142.251.32.83 TLSv1 236 Client Hello

Breaking the "Client Hello" down (well some of it). 
The hello messages are used to exchange security capabilities and enhancements between the client and server. The client's hello message must be responded to by the server's hello message. If there is no response, the connection will fail. The client and server hello messages, establishes the protocol version, session ID, cipher suites and compression methods to be used. 

While the client normally will first send its hello as shown above, in TLSv1.0 the server may send a "Hello Request" asking the client to begin the negotiation process anew.

Both the client and server also generate their respective random values ClientHello.random and Server.Hello.random

While there is a lot in there, we are going to focus on the most important items at this time, for the purpose of this conversation.

┌──(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

1: Content Type: Because TLS was designed to allow extensions to the protocol, new content types can be added. If the other side of a TLS implementation receives a record type it does not understand, it should ignore it. 

Four content types are defined by default: 
* Handshake Protocol
* Alert protocol
* Change Cipher Spec Protocol
* Application Data Protocol

2: Version: For TLSv1.0 record layer version information shows ... well ... TLS 1.0. However, looking at the brackets we see 0x0301. TLS 1.0 is a minor modification to SSL 3.0.

3: Length: The length of the TLS client protocol coming next. In this case, the handshake. It has a length of 177 bytes. This fragment length should not exceed 2**14.

4: Handshake Type: Client Hello (1): There are various handshake types, such as hello_request, client_hello, server_hello, certificate, server_key_exchange, certificate_request, server_hello_done, certificate_verify, client_key_exchange and finished.

Above, we see the type is Client Hello

5: Length: 173: There are 173 bytes coming beyond this

6: Version: TLS 1.0 (0x0301) : This represents the TLS handshake protocol version. This shows TLS_1_0 is being used .

7: GMT Unix Time : This represents the current time and date in seconds, since January 1, 1970 according to the client's internal clock. Interestingly, these internal clocks are not required to be set correctly. Well that is good to know. If you look closely above, it says Sep 8, 2081.

8: Random: A 28 byte value generated by a secure random number generator. 

9: Session ID Length: When not 0 as is shown above, this session ID identifies a connection between two peers for which the client wishes to reuse the security parameters used to create the original session. This identifier may have been from a previous, current or another currently active session. Considering the third option, clients may create several independent secure connections without repeating the full handshake. In this case, the client wishes to start a new connection

10: Cipher Suites Length: This represents the length in the number of bytes occupied by all the cipher suites the client is sending to the server. In this case we have 54.

11: Cipher Suites: We see 27 cipher suites being passed by the client. These are cryptographic algorithms supported by the client and passed to the server in the client's order of preference. Meaning "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)" is what the client wishes to use first. The cipher suites passed defines the key exchange algorithm (ECDHE), the authentication algorithm (ECDSA), the bulk encryption algorithm, including the secret key length (AES_256_CBC) and the hashing algorithm (SHA). The server will choose one from the list. If no acceptable cipher suite is found by the server, a failure alert will be sent and the connection closed.

12: Compression Methods Length: The number of bytes occupied by the Compression Methods. In this case, we see 1 byte.

13: Compression Methods (1 method): This represents how many compression methods are defined. 

14: Compression Method: Currently, no compression method is defined. Hence null (0). If there were multiple, like the cipher suites, they would be placed in the order of preference.

15: Extensions Length: I will not focus on the extension at this time. However, currently there are 78 defined.

With that understanding of the key fields within the TLS Client Hello. Let's look now at the server hello.

For the Client Hello, our Tshark filter was "handshake.type == 1", for the Server Hello, our handshake type will be 2.

┌──(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)
						....


Above shows a sequence (chain) of 3 certificates. The sender's www.securitynik.com certificate comes first. Hence, from to top bottom, the certificate for the domain www.securitynik.com followed by the intermediate CA (GTS CA 1D4) and the root CA (GTS Root R1). Each following certificate certifies the one preceeding it.

The server must send its certificate, providing the agreed upon key exchange method is not anonymous. The server certificate should always be sent.

The certificate provided is generally an X.509v3 certificate. Note, the client may also send a certificate upon request from the server. In this scenario, this is not being done.

Looking at the Server Key Exchange.

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

The Client key exchange message is always sent by the client. If RSA is used, the client generates a 48 bytes premaster secret. This premaster secret will be encrypted with the certificate RSA public key and transmitted to the server. This premaster secret is used to generate the master secret.

In this example, we see Diffie-Helman is being used for the Client Key Exchange. Do remember, the server sent its Diffile-Hellman parameters during its key exchange. The Diffie-Hellman parameters will allow each side to agree on the same premaster secret.

The size of the master secret will always be 48 bytes in length. The length of the premaster secret varies based on the key exchange algorithm.

When RSA is used for authentication and key exchange, the premaster secret is 48 bytes. For Diffie-Hellman the negotiated key size is used as the premaster secret. This is then converted into the master secret.

The client also sends it Change Cipher Spec message

    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

What that understanding in place, time to move to TLSv1.3


TLS 1.3
 
Released via RFC 8446.

TLS 1.3 represents a major revision of the TLS protocol. While TLS 1.3 has significant changes, the basic capabilities for previous TLS version has been retained.

Some key objectives of TLS 1.3 are:
* Remove unused and unsafe features of older TLS version
* Include strong security analysis in the design
* Improve privacy by encrypting more of the protocol
* Reduce the time needed to complete the handshake.
* All handshake messages after the Server Hello are now encrypted. There is also the ability to encrypt extensions messages which were previously sent in the clear via the EncryptedExtensions message. 

TLS 1.3 also has a new set of cipher suites that are exclusive to it. These cipher suites are based on Authenticated Encryption with Associated Data (AEAD).

With the exception of the messages which are needed to establish a shared secret, the TLS handshake is encrypted.

Additionally, items such as renegotiation, generic data compression, Digital Signature Algorithm (DSA) certificates, static RSA key exchange and key exchange with custom Diffie-Hellman (DH) groups have been removed. TLS 1.3 also supports forward secrecy.

The TLS1.3 handshake should be looked at as having 3 phases.
1. Key Exchange
Selection of cryptographic parameters and establishment of a shared key.
2. Server Parameters
Establish other handshake parameters such as application layer protocol support, whether the client should be authenticated, etc. This phase is encrypted.
3. Authentication
Authenticate the server and optionally the client, provide key confirmation and handshake integrity. This phase is also encrypted.


Capture TLSv1.3 Traffic. 

┌──(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

This is the default for curl. Let's still force it.

┌──(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

1: Similar to TLS 1.0, we see the record layer reports a version of TLS 1.0 (0x0301). 

2: In the Handshake Protocol, we see version 1.2 (0x0303) for TLS 1.2. In reality, this version field is considered legacy in TLS 1.3. TLS 1.3 instead leverages the "supported_versions" extension for the client to indicate its preferred version. We see the "supported_versions" extension number 9 above. At a minimum, the ClientHello message will contain a "supported_versions" extension. Only if this extension exists, then the servers will attempt to negotiate TLS 1.3

3: Random Bytes: One of the things this is used for is protection against replay for TLS 1.3 1-RTT data.

4: Session ID: The session_id field is also considered legacy in TLSv1.3. As we saw with TLSv1.0, the ability to resume a session existed. The value we see above would be from a pre TLSv_1.3 session. TLSv1.3 does not support session resumption.

5: Cipher Suites (4 suites): This is the list of symmetric cipher suites supported by the client, the length and the hash algorithms to be used. As with TLSv1.0, these are in the order of client preference.

6: Compression methods are also considered legacy in TLS 1.3

7: Extensions: TLS 1.3 makes extensive use of extensions. TLS 1.3 makes some extensions mandatory, since functionality has moved into these extensions, so as to preserve compatability with previous versions of TLS. If a server does not recognize an extension, the server should just ignore it.

8:  supported_groups: The client uses this group to indicate the named groups the client supports for key exchange. As with the cipher suites and the signature algorithms, it is ordered by most preferred to least preferred. In this list, we have x25519 as the first item.

9: signature_algorithms: This identifies the signature algorithms maybe used in digital signatures. In this example, the signature_algorithms also refers to the signatures appearing in certificates as their is no "signature_algorithms_cert" extension. If the client requires the server to authenticate itself via a certifiates, then the client must send this signature_algorithms extension. If the server is authenticating via a certificate but the client has not sent this extention then then server MUST abort this handshake with a "missing_extension". 

9: supported_versions: As mentioned in 2, this is used by the client to indicate which version of TLS is supports and by the server to specify the version it is using.

10: key_share: This identifies the endpoint cryptographic parameters. The Key exchange inforamation is determed by the group and its corresponding definition. We see here that the server has generated it's "key_share" based on the group x25519 which was the first group identified in 8 above. This key_share represents the client thinking it knows what cipher suite the server is going to choose based on the list the client provides. In this case we see one key_share.

A combination of the Client Hello and Server Hello messages are use to determine the shared keys.

With that understanding of the Client Hello, taking a quick glance at the Server Hello message.

┌──(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]

With all of this understanding now out of the way, let's look to decrypting this communication. 

Before we decrypt anything, if I said to you, "we could see traffic occurring over port 443 without decrypting", you may say that is not possible because we know port 443 traffic is normally encrypted. This is correct. However, what we should notice above in our earlier learning, is that when this connection is starting up, it is in clear text. There is also an extension called "Server Name Indication extension"

┌──(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"


Launching curl ...

┌──(kali㉿securitynik)-[~]
└─$ curl --silent https://www.securitynik.com  --tlsv1.3 --tls-max 1.3 --output /tmp/index.txt

Revisiting SSLKEYLOGFILE, we see.

┌──(kali㉿securitynik)-[~]
└─$ ls sslkeylog.file -l
-rw-r--r-- 1 kali kali 938 Jul 24 14:00 sslkeylog.file

Looking inside the file we see one entry for our curl session;

┌──(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
===================================================================

Clearly, beyond the "tls" we are unable to conclude what type of traffic is following TLS. Let's fix that by leveraging the sslkeylog.file we created via the SSLKEYLOGFILE environment variable. We need to overwrite the TShark configuration by telling it to use the sslkeylog.file as input for decryption.

┌──(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
===================================================================

Whow! We see now we can see all the application layer data as HTTP2. What can I do with this now? Well if I wanted to do signature based analysis we could. Let's say we are aware of the threat actor's attack tool contains a string/signature "securitynik". Do note, you can feed the same file to Wireshark and it can also decrypt the traffic.

Let's first reassembled the session by following the TLS stream.

┌──(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>


We should recognize immediately, we are able to see the plaintext. Remember, this should have all been encrypted.

With the session reassembled, we can now use our signature based analysis tools such as your favourite IDS/IPS such as Snort, Network Monitoring Framesworks such as Zeek or Next Generation Firewall to inspect this traffic.

Let's use grep as our signature based detection tool, looking for the string/pattern "securitynik"

┌──(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

There we go, we decrypted the traffic running over TLS 1.3.

Ok! At this point, you are probably saying but Nik I work mostly in a Windows environment. How do I do this in Windows? Let's address this concern.

Setting and verifying the environment variable on Windows11 under the user profile.

Before setting the environment variable, let's verify that Microsoft Edge browser is not running. Sometimes this seems to cause an issue if we add the environment variable while edge is running.

Getting the process information via both cmd and powershell. Just to show different ways.

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 

Imagine that, all I did was start-up my computer. Did not open a browser but I have 7 instances of MSEdge running. Geez!!!

Back to regular programming. Kill those processes

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.

Set the environment variable

PS C:\Users\Administrator> setx SSLKEYLOGFILE "$(get-location)\sslkeylog_file.txt"  
SUCCESS: Specified value was saved.    

Validate in a Powershell or CMD a new windows the environment variable has been set 

C:\Users\SecurityNik>set|findstr /i ssl
SSLKEYLOGFILE=C:\Users\SecurityNik\sslkeylog_file.txt

With everything in place, let's use Invoke-WebRequest in Powershell, similar to what was done in curl.

PS C:\Users\Administrator> Invoke-WebRequest -uri https://www.securitynik.com -OutFile index.html

What is funny in this situation, is this action did not create the file. I was very much surprised by this. Maybe more testing on my part in the future.

PS C:\Users\Administrator> dir ssl*.*

However, if I open MSEdge, this file gets created and populated.

C:\Users\Administrator>dir ssl*.* /b
sslkeylog_file.txt  

If I run invoke-webrequest in another Terminal while edge is running it appends the new keys to the file. This invoke-webrequest will require more testing as my results are inconsistent. Not interested in this right now as everything works from within MSEdge.

Let's wrap up this post by looking at decrypting via a proxy and a browser.

In this case I am using Burp Suite Community Edition for my proxy

------ BurpProxy On image ------

Validate the proxy is listening via ss

┌──(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))   

Configure the browser to use the proxy.


In my browser, I try to go to https://www.securitynik.com and I see the request is intercepted by the proxy. 




At this point, some people may say "Advanced" and "Accept the Risk and Continue" the attempt to accept the error. That could be a bad move.  Let's do so however for the purpose of this blog post. With the risk being accepted.

Forward the intercepted request within the proxy ...


... and now we see in Burpe also the response in clear text. Because we forwarded the request.



While I captured the traffic from my blog, the takeaway for you is, once a proxy is in place, then you should be aware that the traffic can not only be seen but also manipulated. This is true, even if TLS is in use. 

But what about HTTP Strict Transport Security (HSTS)?

HSTS is a response header sent by the server, stating that the site should only be accessed using HTTPS. HSTS can be used to mitigate the risk of man-in-the-middle types of attacks.

The browser will reports that the site supports HSTS and thus if we wanted to access that site, we would have to create an exception. 


References: