=======
ssl.log
=======

In the section discussing the :file:`http.log`, we noted that most HTTP traffic
is now encrypted and transmitted as HTTPS. Zeek does not create a
:file:`https.log`, because Zeek (or other network inspection tools, for that
matter) does not natively recognize HTTP when it is encrypted as HTTPS.

HTTPS is most often encrypted using Transport Layer Security (TLS), which
presents many variants in live traffic. Zeek parses TLS traffic and records its
findings in the :file:`ssl.log`. SSL refers to Secure Sockets Layer, an
obsolete predecessor to TLS.

TLS is not restricted to encrypting HTTPS, however. Many other protocols use
TLS to encrypt their contents, including Simple Mail Transfer Protocol (SMTP).

Remember that to see the meaning of each field in the :file:`ssl.log`, check
:zeek:see:`SSL::Info`.

Reviewing TLS Versions Seen on the Network
==========================================

To get an idea of the sorts of TLS traffic running in my network, I ran the
following command to search hundreds of days of Zeek :file:`ssl.log` entries:

.. code-block:: console

  $ for i in $(find . -name ssl*.log.gz); do zcat $i; done | jq '[."version"]' | grep -v "\]" | grep -v "\[" | sort -n | uniq -c | sort -rn

::

  11279341   "TLSv12"
  2877117   "TLSv13"
   303084   "unknown-64282"
   198154   null
    23181   "TLSv10"
     5756   "TLSv11"
      348   "DTLSv12"
       78   "DTLSv10"

TLS 1.0 and 1.1 are obsolete. TLS 1.2 and 1.3 are common, with 1.3 gaining
ground on 1.2 DTLS is a variant used to encrypt UDP traffic. ``unknown-64282``
is apparently a Facebook-created variant of TLS 1.3. Almost 20,000 connections
advertised no TLS version, but were recognized by Zeek as some form of TLS.

To try to see what protocols the TLS might be encrypting, I ran the following
command to search 10 days of Zeek :file:`ssl.log` entries:

.. code-block:: console

  $ for i in $(find ./2020-08-1* -name ssl*.log.gz); do zcat $i; done | jq -c '[."version", ."next_protocol"]' | sort -n | uniq -c | sort -rn

::

   246868 ["TLSv12",null]
   144291 ["TLSv13",null]
    86708 ["TLSv12","http/1.1"]
    85082 ["TLSv12","h2"]
     8450 ["unknown-64282",null]
     1966 [null,null]
      722 ["TLSv12","apns-pack-v1:4096:4096"]
      504 ["TLSv10",null]
      234 ["TLSv10","http/1.1"]
      154 ["TLSv12","grpc-exp"]
       83 ["TLSv11",null]
       13 ["DTLSv12",null]

``HTTP/1.1`` is obviously HTTP. The ``h2`` entry refers to the newer HTTP/2
protocol. The ``apns-pack-v1:4096:4096`` entry appears to refer to Apple Push
Notification Service, which utilizes Application Layer Protocol Negotiation
(ALPN), a TLS extension. The ``grpc-exp`` entry appears to refer to another
ALPN method that uses the gRPC remote procedure call (RPC) library.

With this brief look at the types of TLS traffic one might find in a network
done, it’s time to look at a sample connection that generates a :file:`ssl.log` entry.

Preparing to Inspect the :file:`ssl.log`
========================================

To generate network traffic that uses TLS encryption, I retrieved the index
page of the https://www.taosecurity.com using :program:`curl`.

After processing the traffic with Zeek, I had several log files to analyze.
First let’s look at the :file:`conn.log`. We will focus on the Web session
itself, and not related traffic like any DNS lookups required to resolve the
hostname to an IP address.

::

  {
    "ts": 1598377391.716515,
    "uid": "CsukF91Bx9mrqdEaH9",
    "id.orig_h": "192.168.4.49",
    "id.orig_p": 56718,
    "id.resp_h": "13.32.202.10",
    "id.resp_p": 443,
    "proto": "tcp",
    "service": "ssl",
    "duration": 0.497269868850708,
    "orig_bytes": 929,
    "resp_bytes": 31113,
    "conn_state": "SF",
    "missed_bytes": 0,
    "history": "ShADadfF",
    "orig_pkts": 37,
    "orig_ip_bytes": 2861,
    "resp_pkts": 34,
    "resp_ip_bytes": 32889
  }

We have a client, ``192.168.4.49``, interacting with a server,
``13.32.202.10``, offering an encrypted service on port 443 TCP. Zeek reports
this as ``ssl``, but that is a generic term that applies to TLS as well. We can
use the connection identifier, ``CsukF91Bx9mrqdEaH9``, to find associated Zeek
logs.

Inspecting the :file:`ssl.log` When TLS 1.2 Applies
===================================================

Using the connection identifier, we find the associated :file:`ssl.log` entry
for this conversation.

::

  {
    "ts": 1598377391.921726,
    "uid": "CsukF91Bx9mrqdEaH9",
    "id.orig_h": "192.168.4.49",
    "id.orig_p": 56718,
    "id.resp_h": "13.32.202.10",
    "id.resp_p": 443,
    "version": "TLSv12",
    "cipher": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
    "curve": "secp256r1",
    "server_name": "www.taosecurity.com",
    "resumed": false,
    "next_protocol": "h2",
    "established": true,
    "cert_chain_fuids": [
      "F2XEvj1CahhdhtfvT4",
      "FZ7ygD3ERPfEVVohG9",
      "F7vklpOKI4yX9wmvh",
      "FAnbnR32nIIr2j9XV"
    ],
    "client_cert_chain_fuids": [],
    "subject": "CN=www.taosecurity.com",
    "issuer": "CN=Amazon,OU=Server CA 1B,O=Amazon,C=US"
  }

This is a rich log entry that tells us a lot about the connection. We see that
the server and client agree to speak TLS 1.2, with the designated cipher suite
and elliptic curve. The server name, ``www.taosecurity.com`` appears, which
matches the subject of the certificate presented by the Web server. We can see
that Amazon issued the certificate. The next protocol involved was HTTP/2, as
the ``next_protocol`` field lists ``h2``. Zeek provides file identifiers for
the four certificates that the server presented to the client. The client did
not present any certificates to the server.

We will use the certificate information when we look at the next log in our
series, the :file:`x509.log`.

Inspecting the :file:`ssl.log` When TLS 1.3 Applies
===================================================

The last section showed Zeek’s :file:`ssl.log` when visiting a server that
negotiated a TLS 1.2 connection. The following example shows how the situation
changes when the parties use TLS 1.3.

To generate the traffic, I used :program:`curl` with a switch to try TLS 1.3
encryption.

.. code-block:: console

  $ curl -v --tlsv1.3 https://www.taosecurity.com

:program:`curl` provided the following, in addition to the content of the Web
site:

::

  * Connected to www.taosecurity.com (13.32.202.2) port 443 (#0)
  * ALPN, offering h2
  * ALPN, offering http/1.1
  * successfully set certificate verify locations:
  *   CAfile: C:\ProgramData\chocolatey\lib\curl\tools\curl-7.72.0-win64-mingw\bin\curl-ca-bundle.crt
    CApath: none
  } [5 bytes data]
  * TLSv1.3 (OUT), TLS handshake, Client hello (1):
  } [512 bytes data]
  * TLSv1.3 (IN), TLS handshake, Server hello (2):
  { [122 bytes data]
  * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
  { [19 bytes data]
  * TLSv1.3 (IN), TLS handshake, Certificate (11):
  { [4880 bytes data]
  * TLSv1.3 (IN), TLS handshake, CERT verify (15):
  { [264 bytes data]
  * TLSv1.3 (IN), TLS handshake, Finished (20):
  { [36 bytes data]
  * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
  } [1 bytes data]
  * TLSv1.3 (OUT), TLS handshake, Finished (20):
  } [36 bytes data]
  * SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
  * ALPN, server accepted to use h2
  * Server certificate:
  *  subject: CN=www.taosecurity.com
  *  start date: Jun  1 00:00:00 2020 GMT
  *  expire date: Jul  1 12:00:00 2021 GMT
  *  subjectAltName: host "www.taosecurity.com" matched cert's "www.taosecurity.com"
  *  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
  *  SSL certificate verify ok.
  * Using HTTP2, server supports multi-use
  * Connection state changed (HTTP/2 confirmed)
  * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
  } [5 bytes data]
  * Using Stream ID: 1 (easy handle 0x1f9ff0c7600)
  } [5 bytes data]
  > GET / HTTP/2
  > Host: www.taosecurity.com
  > user-agent: curl/7.72.0
  > accept: */*
  >
  { [5 bytes data]
  * Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
  } [5 bytes data]
  < HTTP/2 200
  < content-type: text/html
  < content-length: 28708
  < date: Tue, 01 Sep 2020 18:07:59 GMT
  < last-modified: Tue, 01 Sep 2020 14:36:01 GMT
  < etag: "9a6a530f507d79ba54daa5872b3cad22"
  < accept-ranges: bytes
  < server: AmazonS3
  < vary: Accept-Encoding
  < x-cache: Miss from cloudfront
  < via: 1.1 c09a013ad199e52fd50ddc5543a72f45.cloudfront.net (CloudFront)
  < x-amz-cf-pop: IAD66-C1
  < x-amz-cf-id: wXc1bcKla5qIePZ29LBk1fgATzgf1jLYiRvSmnyZcb7Q1eB_ZJSbaA==
  <
  { [16032 bytes data]

Note that the certificate details are visible here, because we are looking from
the perspective of the Web client, not a passive network observation system.

Here is the :file:`conn.log`:

::

  {
    "ts": 1598983678.546522,
    "uid": "CcJfBs3hXLJn7oHVu7",
    "id.orig_h": "192.168.4.142",
    "id.orig_p": 58802,
    "id.resp_h": "13.32.202.2",
    "id.resp_p": 443,
    "proto": "tcp",
    "service": "ssl",
    "duration": 0.13053107261657715,
    "orig_bytes": 831,
    "resp_bytes": 34650,
    "conn_state": "SF",
    "missed_bytes": 0,
    "history": "ShADadFf",
    "orig_pkts": 17,
    "orig_ip_bytes": 1523,
    "resp_pkts": 30,
    "resp_ip_bytes": 35862
  }

Here is the :file:`ssl.log`:

::

  {
    "ts": 1598983678.585087,
    "uid": "CcJfBs3hXLJn7oHVu7",
    "id.orig_h": "192.168.4.142",
    "id.orig_p": 58802,
    "id.resp_h": "13.32.202.2",
    "id.resp_p": 443,
    "version": "TLSv13",
    "cipher": "TLS_AES_128_GCM_SHA256",
    "curve": "x25519",
    "server_name": "www.taosecurity.com",
    "resumed": true,
    "established": true
  }

Note that there is no mention of certificates in the :file:`ssl.log`. TLS 1.3
hides these from passive observation systems. We are able to see the server
name, ``www.taosecurity.com``, however, as well as some information about the
encryption used. These include the TLS version, the cipher, and the elliptic
curve.

Inspecting the :file:`ssl.log` When ESNI/ECH Applies
====================================================

There is one more concern for an analyst working with the :file:`ssl.log`.

Encrypted Server Name Indication (ESNI) or Encrypted Client Hello (ECH) are
methods by which the Server Name Identification field is no longer sent as
plain text. The mechanics of this process are less important than the effects
on Zeek :file:`ssl.log` entries.

To generate traffic for this example, I used a modern version of Firefox,
configured to support ESNI, and visited a Web site,
``https://only.esni.defo.ie/``, that only accepts connections from systems
supporting ESNI.

After processing the traffic with Zeek, I had the following logs.

First, I had two :file:`conn.log` entries::

  {"ts":1598631659.652789,"uid":"Cg9oVc87cdxWf5Dla","id.orig_h":"192.168.4.142","id.orig_p":63213,"id.resp_h":"185.24.233.103","id.resp_p":443,"proto":"tcp","service":"ssl","duration":5.702061891555786,"orig_bytes":1467,"resp_bytes":3160,"conn_state":"SF","missed_bytes":0,"history":"ShADadTtFf","orig_pkts":11,"orig_ip_bytes":2347,"resp_pkts":8,"resp_ip_bytes":4645}

  {"ts":1598631659.331871,"uid":"Cixuvq2LQrbqxU4Y17","id.orig_h":"192.168.4.142","id.orig_p":63210,"id.resp_h":"185.24.233.103","id.resp_p":443,"proto":"tcp","service":"ssl","duration":6.023154020309448,"orig_bytes":2193,"resp_bytes":45269,"conn_state":"SF","missed_bytes":0,"history":"ShADadFf","orig_pkts":14,"orig_ip_bytes":2765,"resp_pkts":37,"resp_ip_bytes":46761}

Second, I had two :file:`ssl.log` entries::

  {
    "ts": 1598631659.431907,
    "uid": "Cixuvq2LQrbqxU4Y17",
    "id.orig_h": "192.168.4.142",
    "id.orig_p": 63210,
    "id.resp_h": "185.24.233.103",
    "id.resp_p": 443,
    "version": "TLSv13",
    "cipher": "TLS_AES_256_GCM_SHA384",
    "curve": "x25519",
    "resumed": true,
    "established": true
  }
  {
    "ts": 1598631659.752715,
    "uid": "Cg9oVc87cdxWf5Dla",
    "id.orig_h": "192.168.4.142",
    "id.orig_p": 63213,
    "id.resp_h": "185.24.233.103",
    "id.resp_p": 443,
    "version": "TLSv13",
    "cipher": "TLS_AES_256_GCM_SHA384",
    "curve": "x25519",
    "resumed": true,
    "established": true
  }

As you can see, there is no identifying information in the :file:`ssl.log`
here. There are no certificate identifier entries either, although we will talk
about that log type in the next section. As the visit to
``https://only.esni.defo.ie/`` also used DNS over HTTPs (DoH), there is no DNS
record showing the identity of the remote server, as might be revealed in a
conventional DNS request and response.

As you might expect, this situation has some network security monitoring
practitioners concerned by the loss of visibility, and the opportunity for
intruders to leverage ESNI-enabled servers and Doh-enabled clients to evade
inspection.

Leveraging JA3 and JA3S
=======================

JA3 and JA3S are mechanisms to profile the TLS implementations on clients and
servers, respectively. These are clever tools to tell analysts more about each
end of a connection. To learn more, see the following project page:

https://github.com/salesforce/ja3

When running Zeek with the JA3 and JA3S packages, the scripts will append data
to the :file:`ssl.log` as follows.

In the first example, a Web client (curl) connects to the Google Web site using
TLS 1.3. The :file:`ssl.log` shows the following entry.

.. literal-emph::

  {
    "ts": "2020-09-16T14:01:26.194646Z",
    "uid": "CH3QeG4kCxFL8eZrs1",
    "id.orig_h": "192.168.4.37",
    "id.orig_p": 58842,
    "id.resp_h": "172.217.15.100",
    "id.resp_p": 443,
    "version": "TLSv13",
    "cipher": "TLS_AES_256_GCM_SHA384",
    "curve": "x25519",
    "server_name": "www.google.com",
    "resumed": true,
    "established": true,
    **"ja3": "3830b2a4fbcea64e74db382e467f5b3b",**
    **"ja3s": "907bf3ecef1c987c889946b737b43de8"**
  }

Zeek computes the JA3 (client) and JA3S (server) hashes as shown.

In the second example, the same Web client connects to the Corelight Web site.

.. literal-emph::

  {
    "ts": "2020-09-16T13:58:21.878466Z",
    "uid": "CtbyI4sDwTIPROUv6",
    "id.orig_h": "192.168.4.37",
    "id.orig_p": 49572,
    "id.resp_h": "99.86.230.78",
    "id.resp_p": 443,
    "version": "TLSv13",
    "cipher": "TLS_AES_128_GCM_SHA256",
    "curve": "x25519",
    "server_name": "www.corelight.com",
    "resumed": true,
    "established": true,
    **"ja3": "3830b2a4fbcea64e74db382e467f5b3b",**
    **"ja3s": "f4febc55ea12b31ae17cfb7e614afda8"**
  }

The JA3 (client) hash has stayed the same, but the JA3S (server) hash has
changed.

In the third example, the same Web client connects to the TaoSecurity Web site.

.. literal-emph::

  {
    "ts": "2020-09-16T13:54:57.033503Z",
    "uid": "CXc63QyS40XspAmcd",
    "id.orig_h": "192.168.4.37",
    "id.orig_p": 41608,
    "id.resp_h": "99.84.222.6",
    "id.resp_p": 443,
    "version": "TLSv13",
    "cipher": "TLS_AES_128_GCM_SHA256",
    "curve": "x25519",
    "server_name": "www.taosecurity.com",
    "resumed": true,
    "established": true,
    **"ja3": "0bae189478c11bed9d6259ae0ffc9493",**
    **"ja3s": "f4febc55ea12b31ae17cfb7e614afda8"**
  }

This is an odd result. The JA3 (client) hash has changed, but the JA3S (server)
hash has stayed the same. I can explain the server hash staying the same by
noting that both the Corelight and TaoSecurity Web sites appear to be hosted by
Amazon, meaning the Web servers providing each site are offering the same TLS
parameters.

However, I would have expected the JA3 (client) hash to have been the same as
the previous two examples. I repeated the connection and got the same JA3 and
JA3S hashes.

Conclusion
==========

This section showed that the default :file:`ssl.log` provides several details
of interest to defenders, even when inspecting encrypted traffic. As
administrators and intruders deploy newer encryption technologies, however,
defenders will find it increasingly difficult to differentiate among normal,
suspicious, and malicious traffic.
