mirror of
https://github.com/zeek/zeek.git
synced 2025-10-06 08:38:20 +00:00

This is based on commit 2731def9159247e6da8a3191783c89683363689c from the zeek-docs repo.
459 lines
16 KiB
ReStructuredText
459 lines
16 KiB
ReStructuredText
=======
|
||
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.
|