Using Wazuh and Heartbeat to monitor SSL/TLS certificates.

Vlad Spades
System Weakness
Published in
5 min readJun 5, 2022

--

Introduction

SSL is a protocol used to secure communication between a server and a client in a network. Since SSL/TLS is a hybrid of PKI and symmetric cryptography, it makes use of digital certificates. A good example of SSL/TLS implementation is HTTPS. HTTPS is used to verify the identity of a web server and secure the exchange of sensitive data between the web server and a client.

Attackers can still compromise server-client communication if a server uses an SSL/TLS certificate:

  • That is expired.
  • Issued by an unknown or untrusted certificate authority.
  • That has an insecure version like TLS 1.0 and TLS 1.1.

Therefore, it is important to verify that SSL/TLS certificates used across a network are secure at all times. This blog post details how Wazuh and Heartbeat can be configured to monitor and alert the status of SSL/TLS certificates.

Infrastructure components

  1. Wazuh server 4.3.3: Wazuh is a unified SIEM and XDR platform that provides endpoint security and visibility. This will be used to analyze data produced by Heartbeat. It will generate alerts for bad and insecure SSL certificates. Rules and decoders will be configured on the Wazuh server side.
  2. Heartbeat OSS-only 7.10.0: This tool is used to collect uptime data of services. It accomplishes this by continuously probing the services. In this blog post, we will use it to probe the HTTPS protocol.
  3. Ubuntu 20.04 server: This is where Heartbeat OSS-only and the Wazuh agent are installed. The Wazuh agent is to be enrolled/connected to the Wazuh server.
Wazuh dashboard showing the enrolled agent

Configuration

Configure Heartbeat

Download Heartbeat OSS-only on the Ubuntu server:

# wget https://artifacts.elastic.co/downloads/beats/heartbeat/heartbeat-oss-7.10.0-amd64.deb

Install Heartbeat:

# dpkg -i heartbeat-oss-7.10.0-amd64.deb

We need to create a monitor that will check the status of SSL/TLS certificates of the websites specified. Create and edit a configuration file called /etc/heartbeat/ssl_monitoring.yml:

heartbeat.config.monitors:
path: ${path.config}/monitors.d/*.yml
reload.enabled: false
reload.period: 5s
heartbeat.monitors:
- type: http
id: ssl_tls
name: SSL Monitoring
schedule: '@every 10s'
urls:
- https://self-signed.badssl.com/
- https://expired.badssl.com
- https://revoked.badssl.com/
- https://wrong.host.badssl.com/
setup.kibana:
host: "localhost:5601"
logging.level: debug
logging.to_files: true
logging.files:
path: /var/log/heartbeat/ssl_monitoring
name: heartbeat
keepfiles: 2
permissions: 0644
output.file:
path: "/tmp"
filename: to-be-deleted
rotate_every_kb: 10
permissions: 0644
#rotate_on_startup: true

The configuration above contains the following:

  • heartbeat.monitors.type: specifies the type of monitor used.
  • heartbeat.monitors.id: specifies the id of the monitor.
  • heartbeat.monitors.name: specifies the name of the monitor.
  • heartbeat.monitors.schedule: this is the frequency at which the monitor will check the status of the certificates.
  • heartbeat.monitors.urls: this specifies the URLs or domains to monitor. Note that the HTTPS before the URL/domain is what instructs Heartbeat to check for SSL/TLS information. Subdomains from https://badssl.com/ were used for illustration.
  • logging.level: this is set to debug so the responses from Heartbeat probes for SSL/TLS information are logged.
  • logging.files.path: specifies where all Heartbeat responses should be logged.
  • logging.files.file: specifies the log file for Heartbeat.
  • output.file.filename: specifies the file a particular Heartbeat monitor outputs to. This is not important in this setup, logging.files.file is the file that needs to be analyzed by the Wazuh server.

Configure log collection

We add the configuration below to the /var/ossec/etc/ossec.conf file of the Wazuh agent. This is to specify where to collect logs generated by Heartbeat. The logs created are a mix of Syslog and JSON format. Therefore we will use the multi-line-regex log format to carve out data from the start of useful logs:

<localfile>
<log_format>multi-line-regex</log_format>
<location>/var/log/heartbeat/ssl_monitoring/heartbeat</location>
<multiline_regex match="all" replace="wspace">^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\s+DEBUG\s+\[processors\]\s+processing\/processors.go:\d*</multiline_regex>
</localfile>

We restart the Wazuh agent for changes to apply:

# sudo systemctl restart wazuh-agent

Create custom rules to monitor Heartbeat logs

First, let’s start the Heartbeat service and print logs to the console:

# heartbeat -c ssl_monitoring.yml -e

Look out for debug logs containing SSL/TLS information, see the example log below. We are just checking to make sure the right logs are being produced, then stop Heartbeat:

2022-03-01T11:05:11.562Z        DEBUG   [processors]    processing/processors.go:203    Publish event: {
"@timestamp": "2022-03-01T11:05:10.940Z",
"@metadata": {
"beat": "heartbeat",
"type": "_doc",
"version": "7.10.0"
},
"ecs": {
"version": "1.6.0"
},
"tls": {
"certificate_not_valid_before": "2020-03-23T00:00:00.000Z",
"certificate_not_valid_after": "2022-05-17T12:00:00.000Z",
"established": true,
"rtt": {
"handshake": {
"us": 310926
}
},

On the Wazuh server side, create a custom decoder inside /var/ossec/etc/decoders/local_decoder.xml to parse the Heartbeat logs. The decoder is needed to extract the JSON after Publish event::

<decoder name="heartbeat_log_decoder">
<prematch>Publish\sevent:\s</prematch>
<plugin_decoder offset="after_prematch">JSON_Decoder</plugin_decoder>
</decoder>

Create rules to monitor and generate alerts for bad certificates. Add the rules below to the /var/ossec/etc/rules/local_rules.xml file:

<group name="ssl-monitoring,">
<rule id="100020" level="1">
<decoded_as>heartbeat_log_decoder</decoded_as>
<description>Heartbeat probe.</description>
</rule>
<rule id="100021" level="12">
<if_sid>100020</if_sid>
<field name="tls.version">1.0|1.1</field>
<description>$(url.full) certificate uses an insecure version of TLS: $(tls.version).</description>
<mitre>
<id>T1600</id>
</mitre>
</rule>
<rule id="100022" level="12">
<if_sid>100020</if_sid>
<field name="error.message">certificate has expired or is not yet valid</field>
<description>$(url.full) certificate issued by "$(tls.server.x509.issuer.common_name)" has expired:$(tls.certificate_not_valid_after).</description>
<mitre>
<id>T1600</id>
</mitre>
</rule>
<rule id="100023" level="12">
<if_sid>100020</if_sid>
<field name="error.message">certificate signed by unknown authority</field>
<description>$(url.full) certificate signed by unknown certificate authority.</description>
<mitre>
<id>T1600</id>
</mitre>
</rule>
<rule id="100024" level="12">
<if_sid>100020</if_sid>
<field name="error.message" type="pcre2">(?i)certificate is valid for.+not</field>
<description>Name mismatch error: The SSL/TLS certificate found was not issued for: $(url.full).</description>
<mitre>
<id>T1600</id>
</mitre>
</rule>
</group>

The rules above will detect the following cases:

  1. Insecure versions of SSL/TLS.
  2. Expired certificates.
  3. Certificates signed by unknown certificate authorities.
  4. Name mismatch errors.

Restart the Wazuh manager service for changes to apply:

# sudo systemctl restart wazuh-manager

On the endpoint, start Heartbeat:

# heartbeat -c ssl_monitoring.yml

No alerts will be generated on the Wazuh dashboard but if we check /var/ossec/logs/archives/archives.json or /var/ossec/logs/alerts/alerts.json. We can see that rule alerts are being created. To check, we can grep for heartbeat_log_decoder. The problem is that the Wazuh Filebeat template expects the data.url field as a string type. Instead, the Heartbeat logs have data.url set as an object with multiple entries(port, scheme, domain).

See the end part of an example log captured:

“failed to parse field [data.url] of type [keyword] in document with id ‘UqtwS38Bw7pkM5JPC9iF’. Preview of field’s value: ‘{scheme=https, port=443, domain=pinning-test.badssl.com, full=https://pinning-test.badssl.com}'","caused_by":{"type":"illegal_state_exception","reason":"Can't get text on a START_OBJECT at 1:2341”}}

To solve this problem, navigate to the “Dev Tools” tab on the Wazuh dashboard. The snippet below specifies that the data.url field changes to the data.url_data field only when the heartbeat_log_decoder decoder is executed:

{
"rename": {
"field": "data.url",
"target_field": "data.url_data",
"if": "ctx?.decoder?.name == 'heartbeat_log_decoder'"
}
},

Make an API request to change the fields. Paste the configuration here and click on the “play” icon to send the request.

The schedule option in the Heartbeat configuration file can be set to run once a day. Start Heartbeat:

# heartbeat -c ssl_monitoring.yml

Check the Wazuh dashboard, we can see that alerts are now being displayed:

Wazuh dashboard showing alerts for bad SSL/TLS certificates

Conclusion

This post describes how Wazuh combined with Heartbeat can be used to monitor SSL/TLS certificates. Alerts will be generated on the Wazuh dashboard when certificates are insecure or expired. This is useful to prevent MITM attacks, data leaks and adhere to compliance policies like PCI DSS.

References

  1. https://wazuh.com/
  2. https://documentation.wazuh.com/current/installation-guide/wazuh-agent/wazuh-agent-package-linux.html
  3. https://badssl.com/
  4. https://gist.github.com/Spades0/1d90a55a8050616cdceabf5ef6c91d33

--

--

Cybersecurity Junkie. Constantly finding my self in the middle of malware analysis and technical content writing.