ThreatLockDown central components
Perform the following actions to restore the ThreatLockDown central components data, depending on your deployment type.
Note
For a multi-node setup, there should be a backup file for each node within the cluster. You need root user privileges to execute the commands below.
Single-node data restoration
You need to have a new installation of Wazuh. Follow the Quickstart guide to perform a fresh installation of the ThreatLockDown central components on a new server.
The actions below will guide you through the data restoration process for a single-node deployment.
Preparing the data restoration
Compress the files generated after performing ThreatLockDown files backup and transfer them to the new server:
# tar -cvzf wazuh_central_components.tar.gz ~/wazuh_files_backup/
Move the compressed file to the root
/
directory of your node:# mv wazuh_central_components.tar.gz / # cd /
Decompress the backup files and change the current working directory to the directory based on the date and time of the backup files:
# tar -xzvf wazuh_central_components.tar.gz # cd ~/wazuh_files_backup/<DATE_TIME>
Restoring ThreatLockDown indexer files
Perform the following steps to restore the ThreatLockDown indexer files on the new server.
Stop the ThreatLockDown indexer to prevent any modifications to the ThreatLockDown indexer files during the restoration process:
# systemctl stop wazuh-indexer
Restore the ThreatLockDown indexer configuration files and change the file permissions and ownerships accordingly:
# sudo cp etc/wazuh-indexer/jvm.options /etc/wazuh-indexer/jvm.options # chown wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/jvm.options # sudo cp -r etc/wazuh-indexer/jvm.options.d/* /etc/wazuh-indexer/jvm.options.d/ # chown wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/jvm.options.d # sudo cp etc/wazuh-indexer/log4j2.properties /etc/wazuh-indexer/log4j2.properties # chown wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/log4j2.properties # sudo cp etc/wazuh-indexer/opensearch.keystore /etc/wazuh-indexer/opensearch.keystore # chown wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/opensearch.keystore # sudo cp -r etc/wazuh-indexer/opensearch-observability/* /etc/wazuh-indexer/opensearch-observability/ # chown -R wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/opensearch-observability/ # sudo cp -r etc/wazuh-indexer/opensearch-reports-scheduler/* /etc/wazuh-indexer/opensearch-reports-scheduler/ # chown -R wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/opensearch-reports-scheduler/ # sudo cp usr/lib/sysctl.d/wazuh-indexer.conf /usr/lib/sysctl.d/wazuh-indexer.conf
Start the ThreatLockDown indexer service:
# systemctl start wazuh-indexer
Restoring ThreatLockDown server files
Perform the following steps to restore the ThreatLockDown server files on the new server.
Stop the ThreatLockDown manager and Filebeat to prevent any modification to the ThreatLockDown server files during the restore process:
# systemctl stop filebeat # systemctl stop wazuh-manager
Copy the ThreatLockDown server data and configuration files, and change the file permissions and ownerships accordingly:
# sudo cp etc/filebeat/filebeat.reference.yml /etc/filebeat/ # sudo cp etc/filebeat/fields.yml /etc/filebeat/ # sudo cp -r etc/filebeat/modules.d/* /etc/filebeat/modules.d/ # sudo cp -r etc/postfix/* /etc/postfix/ # sudo cp var/ossec/etc/client.keys /var/ossec/etc/ # chown root:wazuh /var/ossec/etc/client.keys # sudo cp -r var/ossec/etc/sslmanager* /var/ossec/etc/ # sudo cp var/ossec/etc/ossec.conf /var/ossec/etc/ # chown root:wazuh /var/ossec/etc/ossec.conf # sudo cp var/ossec/etc/internal_options.conf /var/ossec/etc/ # chown root:wazuh /var/ossec/etc/internal_options.conf # sudo cp var/ossec/etc/local_internal_options.conf /var/ossec/etc/ # chown root:wazuh /var/ossec/etc/local_internal_options.conf # sudo cp -r var/ossec/etc/rules/* /var/ossec/etc/rules/ # chown -R wazuh:wazuh /var/ossec/etc/rules/ # sudo cp -r var/ossec/etc/decoders/* /var/ossec/etc/decoders # chown -R wazuh:wazuh /var/ossec/etc/decoders/ # sudo cp -r var/ossec/etc/shared/* /var/ossec/etc/shared/ # chown -R wazuh:wazuh /var/ossec/etc/shared/ # chown root:wazuh /var/ossec/etc/shared/ar.conf # sudo cp -r var/ossec/logs/* /var/ossec/logs/ # chown -R wazuh:wazuh /var/ossec/logs/ # sudo cp -r var/ossec/queue/agentless/* /var/ossec/queue/agentless/ # chown -R wazuh:wazuh /var/ossec/queue/agentless/ # sudo cp var/ossec/queue/agents-timestamp /var/ossec/queue/ # chown root:wazuh /var/ossec/queue/agents-timestamp # sudo cp -r var/ossec/queue/fts/* /var/ossec/queue/fts/ # chown -R wazuh:wazuh /var/ossec/queue/fts/ # sudo cp -r var/ossec/queue/rids/* /var/ossec/queue/rids/ # chown -R wazuh:wazuh /var/ossec/queue/rids/ # sudo cp -r var/ossec/stats/* /var/ossec/stats/ # chown -R wazuh:wazuh /var/ossec/stats/ # sudo cp -r var/ossec/var/multigroups/* /var/ossec/var/multigroups/ # chown -R wazuh:wazuh /var/ossec/var/multigroups/
Restore certificates for ThreatLockDown agent and ThreatLockDown server communication, and additional configuration files if present:
# sudo cp -r var/ossec/etc/*.pem /var/ossec/etc/ # chown -R root:wazuh /var/ossec/etc/*.pem # sudo cp var/ossec/etc/authd.pass /var/ossec/etc/ # chown -R root:wazuh /var/ossec/etc/authd.pass
Restore your custom files. If you have custom active response scripts, CDB lists, integrations, or wodles, adapt the following commands accordingly:
# sudo cp var/ossec/active-response/bin/<CUSTOM_ACTIVE_RESPONSE_SCRIPT> /var/ossec/active-response/bin/ # chown root:wazuh /var/ossec/active-response/bin/<CUSTOM_ACTIVE_RESPONSE_SCRIPT> # sudo cp var/ossec/etc/lists/<USER_CDB_LIST>.cdb /var/ossec/etc/lists/ # chown root:wazuh /var/ossec/etc/lists/<USER_CDB_LIST>.cdb # sudo cp var/ossec/integrations/<CUSTOM_INTEGRATION_SCRIPT> /var/ossec/integrations/ # chown root:wazuh /var/ossec/integrations/<CUSTOM_INTEGRATION_SCRIPT> # sudo cp var/ossec/wodles/<CUSTOM_WODLE_SCRIPT> /var/ossec/wodles/ # chown root:wazuh /var/ossec/wodles/<CUSTOM_WODLE_SCRIPT>
Restore the ThreatLockDown databases that contain collected data from the ThreatLockDown agents:
# sudo cp var/ossec/queue/db/* /var/ossec/queue/db/ # chown -R wazuh:wazuh /var/ossec/queue/db/
Start the Filebeat service:
# systemctl start filebeat
Start the ThreatLockDown manager service:
# systemctl start wazuh-manager
Restoring ThreatLockDown dashboard files
Perform the following steps to restore ThreatLockDown reports and custom images on the new server if you have any from your backup.
Restore your ThreatLockDown reports using the following command:
# mkdir -p /usr/share/wazuh-dashboard/data/wazuh/downloads/reports/ # sudo cp -r usr/share/wazuh-dashboard/data/wazuh/downloads/reports/* /usr/share/wazuh-dashboard/data/wazuh/downloads/reports/ # chown -R wazuh-dashboard:wazuh-dashboard /usr/share/wazuh-dashboard/data/wazuh/downloads/
Navigate to Indexer/dashboard management > App Settings > Custom branding from the ThreatLockDown dashboard and upload your custom images.
Restoring old logs
Wazuh, by default, compresses logs that are older than a day. While performing old log restoration in the Restoring ThreatLockDown server files section, the old logs remain compressed.
Perform the following actions on your ThreatLockDown server to decompress these logs and index them in the new ThreatLockDown indexer:
Note
Restoring old logs will have a creation date of the day when the restoration is performed.
Create a Python script called
recovery.py
on your ThreatLockDown server. This script decompresses all the old logs and stores them in therecovery.json
file in the/tmp
directory:# touch recovery.py
Add the following content to the
recovery.py
script:#!/usr/bin/env python import gzip import time import json import argparse import re import os from datetime import datetime from datetime import timedelta def log(msg): now_date = datetime.now().strftime('%Y-%m-%d %H:%M:%S') final_msg = "{0} wazuh-reinjection: {1}".format(now_date, msg) print(final_msg) if log_file: f_log.write(final_msg + "\n") EPS_MAX = 400 wazuh_path = '/var/ossec/' max_size=1 log_file = None parser = argparse.ArgumentParser(description='Reinjection script') parser.add_argument('-eps','--eps', metavar='eps', type=int, required = False, help='Events per second.') parser.add_argument('-min', '--min_timestamp', metavar='min_timestamp', type=str, required = True, help='Min timestamp. Example: 2017-12-13T23:59:06') parser.add_argument('-max', '--max_timestamp', metavar='max_timestamp', type=str, required = True, help='Max timestamp. Example: 2017-12-13T23:59:06') parser.add_argument('-o', '--output_file', metavar='output_file', type=str, required = True, help='Output filename.') parser.add_argument('-log', '--log_file', metavar='log_file', type=str, required = False, help='Logs output') parser.add_argument('-w', '--wazuh_path', metavar='wazuh_path', type=str, required = False, help='Path to Wazuh. By default:/var/ossec/') parser.add_argument('-sz', '--max_size', metavar='max_size', type=float, required = False, help='Max output file size in Gb. Default: 1Gb. Example: 2.5') args = parser.parse_args() if args.log_file: log_file = args.log_file f_log = open(log_file, 'a+') if args.max_size: max_size = args.max_size if args.wazuh_path: wazuh_path = args.wazuh_path output_file = args.output_file #Gb to bytes max_bytes = int(max_size * 1024 * 1024 * 1024) if (max_bytes <= 0): log("Error: Incorrect max_size") exit(1) month_dict = ['Null','Jan','Feb','Mar','Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov','Dec'] if args.eps: EPS_MAX = args.eps if EPS_MAX < 0: log("Error: incorrect EPS") exit(1) min_date = re.search('(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)T\\d\\d:\\d\\d:\\d\\d', args.min_timestamp) if min_date: min_year = int(min_date.group(1)) min_month = int(min_date.group(2)) min_day = int(min_date.group(3)) else: log("Error: Incorrect min timestamp") exit(1) max_date = re.search('(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)T\\d\\d:\\d\\d:\\d\\d', args.max_timestamp) if max_date: max_year = int(max_date.group(1)) max_month = int(max_date.group(2)) max_day = int(max_date.group(3)) else: log("Error: Incorrect max timestamp") exit(1) # Converting timestamp args to datetime min_timestamp = datetime.strptime(args.min_timestamp, '%Y-%m-%dT%H:%M:%S') max_timestamp = datetime.strptime(args.max_timestamp, '%Y-%m-%dT%H:%M:%S') chunk = 0 written_alerts = 0 trimmed_alerts = open(output_file, 'w') max_time=datetime(max_year, max_month, max_day) current_time=datetime(min_year, min_month, min_day) while current_time <= max_time: alert_file = "{0}logs/alerts/{1}/{2}/ossec-alerts-{3:02}.json.gz".format(wazuh_path,current_time.year,month_dict[current_time.month],current_time.day) if os.path.exists(alert_file): daily_alerts = 0 compressed_alerts = gzip.open(alert_file, 'r') log("Reading file: "+ alert_file) for line in compressed_alerts: # Transform line to json object try: line_json = json.loads(line.decode("utf-8", "replace")) # Remove unnecessary part of the timestamp string_timestamp = line_json['timestamp'][:19] # Ensure timestamp integrity while len(line_json['timestamp'].split("+")[0]) < 23: line_json['timestamp'] = line_json['timestamp'][:20] + "0" + line_json['timestamp'][20:] # Get the timestamp readable event_date = datetime.strptime(string_timestamp, '%Y-%m-%dT%H:%M:%S') # Check the timestamp belongs to the selected range if (event_date <= max_timestamp and event_date >= min_timestamp): chunk+=1 trimmed_alerts.write(json.dumps(line_json)) trimmed_alerts.write("\n") trimmed_alerts.flush() daily_alerts += 1 if chunk >= EPS_MAX: chunk = 0 time.sleep(2) if os.path.getsize(output_file) >= max_bytes: trimmed_alerts.close() log("Output file reached max size, setting it to zero and restarting") time.sleep(EPS_MAX/100) trimmed_alerts = open(output_file, 'w') except ValueError as e: print("Oops! Something went wrong reading: {}".format(line)) print("This is the error: {}".format(str(e))) compressed_alerts.close() log("Extracted {0} alerts from day {1}-{2}-{3}".format(daily_alerts,current_time.day,month_dict[current_time.month],current_time.year)) else: log("Couldn't find file {}".format(alert_file)) #Move to next file current_time += timedelta(days=1) trimmed_alerts.close()
While you run the
recovery.py
script, you need to consider the following parameters:usage: recovery.py [-h] [-eps eps] -min min_timestamp -max max_timestamp -o output_file [-log log_file] [-w wazuh_path] [-sz max_size] -eps eps, --eps eps Events per second. Default: 400 -min min_timestamp, --min_timestamp min_timestamp Min timestamp. Example: 2019-11-13T08:42:17 -max max_timestamp, --max_timestamp max_timestamp Max timestamp. Example: 2019-11-13T23:59:06 -o output_file, --output_file output_file Alerts output file. -log log_file, --log_file log_file Logs output. -w wazuh_path, --wazuh_path wazuh_path Path to Wazuh. By default:/var/ossec/ -sz max_size, --max_size max_size Max output file size in Gb. Default: 1Gb. Example: 2.5
Run the command below to make the
recovery.py
script executable:# chmod +x recovery.py
Execute the script using
nohup
command in the background to keep it running after the session is closed. It may take time depending on the size of the old logs.Usage example:
# nohup ./recovery.py -eps 500 -min 2023-06-10T00:00:00 -max 2023-06-18T23:59:59 -o /tmp/recovery.json -log ./recovery.log -sz 2.5 &
Add the
/tmp/recovery.json
path to the ThreatLockDown Filebeat module/usr/share/filebeat/module/wazuh/alerts/manifest.yml
so that Filebeat sends the old alerts to the ThreatLockDown indexer for indexing:module_version: 0.1 var: - name: paths default: - /var/ossec/logs/alerts/alerts.json - /tmp/recovery.json - name: index_prefix default: wazuh-alerts-4.x- input: config/alerts.yml ingest_pipeline: ingest/pipeline.json
Restart Filebeat for the changes to take effect:
# systemctl restart filebeat
Verifying data restoration
Using the ThreatLockDown dashboard, navigate to the Threat Hunting, File Integrity Monitoring, Vulnerability Detection, and any other modules to see if the data is restored successfully.
Multi-node data restoration
Perform the actions below to restore the ThreatLockDown central components on their respective ThreatLockDown nodes.
Preparing the data restoration
Compress the files generated after performing ThreatLockDown files backup and transfer them to the respective new servers:
# tar -cvzf <SERVER_HOSTNAME>.tar.gz ~/wazuh_files_backup/
Where:
<SERVER_HOSTNAME>
represents the current server name. Consider adding the naming convention,_indexer
,_server
,_dashboard
if the current hostnames don’t specify them.
Note
Make sure that ThreatLockDown indexer compressed files are transferred to the new ThreatLockDown indexer nodes, ThreatLockDown server compressed files are transferred to the new ThreatLockDown server nodes, and ThreatLockDown dashboard compressed files are transferred to the new ThreatLockDown dashboard nodes.
Move the compressed file to the root
/
directory of each node:# mv <SERVER_HOSTNAME>.tar.gz / # cd /
Decompress the backup files and change the current working directory to the directory based on the date and time of the backup files:
# tar -xzvf <SERVER_HOSTNAME>.tar.gz # cd ~/wazuh_files_backup/<DATE_TIME>
Restoring ThreatLockDown indexer files
You need to have a new installation of ThreatLockDown indexer. Follow the ThreatLockDown indexer - Installation guide to perform a fresh ThreatLockDown indexer installation.
Perform the following steps on each ThreatLockDown indexer node.
Stop the ThreatLockDown indexer to prevent any modification to the ThreatLockDown indexer files during the restore process:
# systemctl stop wazuh-indexer
Restore the ThreatLockDown indexer configuration files, and change the file permissions and ownerships accordingly:
# sudo cp etc/wazuh-indexer/jvm.options /etc/wazuh-indexer/jvm.options # chown wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/jvm.options # sudo cp etc/wazuh-indexer/jvm.options.d /etc/wazuh-indexer/jvm.options.d # chown wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/jvm.options.d # sudo cp etc/wazuh-indexer/log4j2.properties /etc/wazuh-indexer/log4j2.properties # chown wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/log4j2.properties # sudo cp etc/wazuh-indexer/opensearch.keystore /etc/wazuh-indexer/opensearch.keystore # chown wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/opensearch.keystore # sudo cp -r etc/wazuh-indexer/opensearch-observability/* /etc/wazuh-indexer/opensearch-observability/ # chown -R wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/opensearch-observability/ # sudo cp -r etc/wazuh-indexer/opensearch-reports-scheduler/* /etc/wazuh-indexer/opensearch-reports-scheduler/ # chown -R wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/opensearch-reports-scheduler/ # sudo cp usr/lib/sysctl.d/wazuh-indexer.conf /usr/lib/sysctl.d/wazuh-indexer.conf
Start the ThreatLockDown indexer service:
# systemctl start wazuh-indexer
Restoring ThreatLockDown server files
You need to have a new installation of a ThreatLockDown server. Follow the ThreatLockDown server - Installation guide to perform a multi-node ThreatLockDown server installation. There will be at least one master node and one worker node as node types. Perform the steps below, considering your node type.
Stop the ThreatLockDown manager and Filebeat to prevent any modification to the ThreatLockDown server files during the restore process:
# systemctl stop filebeat # systemctl stop wazuh-manager
Copy ThreatLockDown server data and configuration files, and change the file permissions and ownerships accordingly:
# sudo cp etc/filebeat/filebeat.reference.yml /etc/filebeat/ # sudo cp etc/filebeat/fields.yml /etc/filebeat/ # sudo cp -r etc/filebeat/modules.d/* /etc/filebeat/modules.d/ # sudo cp -r etc/postfix/* /etc/postfix/ # sudo cp var/ossec/etc/client.keys /var/ossec/etc/ # chown root:wazuh /var/ossec/etc/client.keys # sudo cp -r var/ossec/etc/sslmanager* /var/ossec/etc/ # sudo cp var/ossec/etc/ossec.conf /var/ossec/etc/ # chown root:wazuh /var/ossec/etc/ossec.conf # sudo cp var/ossec/etc/internal_options.conf /var/ossec/etc/ # chown root:wazuh /var/ossec/etc/internal_options.conf # sudo cp var/ossec/etc/local_internal_options.conf /var/ossec/etc/ # chown root:wazuh /var/ossec/etc/local_internal_options.conf # sudo cp -r var/ossec/etc/rules/* /var/ossec/etc/rules/ # chown -R wazuh:wazuh /var/ossec/etc/rules/ # sudo cp -r var/ossec/etc/decoders/* /var/ossec/etc/decoders # chown -R wazuh:wazuh /var/ossec/etc/decoders/ # sudo cp -r var/ossec/etc/shared/* /var/ossec/etc/shared/ # chown -R wazuh:wazuh /var/ossec/etc/shared/ # chown root:wazuh /var/ossec/etc/shared/ar.conf # sudo cp -r var/ossec/logs/* /var/ossec/logs/ # chown -R wazuh:wazuh /var/ossec/logs/ # sudo cp -r var/ossec/queue/agentless/* /var/ossec/queue/agentless/ # chown -R wazuh:wazuh /var/ossec/queue/agentless/ # sudo cp var/ossec/queue/agents-timestamp /var/ossec/queue/ # chown root:wazuh /var/ossec/queue/agents-timestamp # sudo cp -r var/ossec/queue/fts/* /var/ossec/queue/fts/ # chown -R wazuh:wazuh /var/ossec/queue/fts/ # sudo cp -r var/ossec/queue/rids/* /var/ossec/queue/rids/ # chown -R wazuh:wazuh /var/ossec/queue/rids/ # sudo cp -r var/ossec/stats/* /var/ossec/stats/ # chown -R wazuh:wazuh /var/ossec/stats/ # sudo cp -r var/ossec/var/multigroups/* /var/ossec/var/multigroups/ # chown -R wazuh:wazuh /var/ossec/var/multigroups/
Restore certificates for ThreatLockDown agent and ThreatLockDown server communication, and additional configuration files if present:
# sudo cp -r var/ossec/etc/*.pem /var/ossec/etc/ # chown -R root:wazuh /var/ossec/etc/*.pem # sudo cp var/ossec/etc/authd.pass /var/ossec/etc/ # chown -R root:wazuh /var/ossec/etc/authd.pass
Restore your custom files. If you have custom active response scripts, CDB lists, integrations, or wodle commands, adapt the following commands accordingly:
# sudo cp var/ossec/active-response/bin/<CUSTOM_AR_SCRIPT> /var/ossec/active-response/bin/ # chown root:wazuh /var/ossec/active-response/bin/<CUSTOM_AR_SCRIPT> # sudo cp var/ossec/etc/lists/<USER_CDB_LIST>.cdb /var/ossec/etc/lists/ # chown root:wazuh /var/ossec/etc/lists/<USER_CDB_LIST>.cdb # sudo cp var/ossec/integrations/<CUSTOM_INTEGRATION_SCRIPT> /var/ossec/integrations/ # chown root:wazuh /var/ossec/integrations/<CUSTOM_INTEGRATION_SCRIPT> # sudo cp var/ossec/wodles/<CUSTOM_WODLE_SCRIPT> /var/ossec/wodles/ # chown root:wazuh /var/ossec/wodles/<CUSTOM_WODLE_SCRIPT>
Restore the ThreatLockDown databases that contain collected data from ThreatLockDown agents:
# sudo cp var/ossec/queue/db/* /var/ossec/queue/db/ # chown -R root:wazuh /var/ossec/queue/db/
Start the Filebeat service:
# systemctl start filebeat
Start the ThreatLockDown manager service:
# systemctl start wazuh-manager
Restoring ThreatLockDown dashboard files
You need to have a new installation of the ThreatLockDown dashboard. Follow ThreatLockDown dashboard - Installation guide to perform ThreatLockDown dashboard installation.
Perform the following steps to restore ThreatLockDown reports and custom images on the new server if you have any from your backup.
Restore your ThreatLockDown reports using the following command:
# mkdir -p /usr/share/wazuh-dashboard/data/wazuh/downloads/reports/ # sudo cp -r usr/share/wazuh-dashboard/data/wazuh/downloads/reports/* /usr/share/wazuh-dashboard/data/wazuh/downloads/reports/ # chown -R wazuh-dashboard:wazuh-dashboard /usr/share/wazuh-dashboard/data/wazuh/downloads/
Navigate to Indexer/dashboard management > App Settings > Custom branding from the ThreatLockDown dashboard and upload your custom images.
Restoring old logs
Wazuh, by default, compresses logs that are older than a day. While performing log restoration in the Restoring ThreatLockDown server files section, the old logs remain compressed.
Perform the following actions on both master and worker nodes of your ThreatLockDown server to decompress the old logs and re-inject them for indexing to the ThreatLockDown indexer.
Note
Restoring old logs will have a creation date of the day when the restoration is performed.
Create a Python script called
recovery.py
on your ThreatLockDown server. This script decompresses all the old logs and stores them in therecovery.json
file in/tmp
directory.# touch recovery.py
Add the following content to the
recovery.py
script:#!/usr/bin/env python import gzip import time import json import argparse import re import os from datetime import datetime from datetime import timedelta def log(msg): now_date = datetime.now().strftime('%Y-%m-%d %H:%M:%S') final_msg = "{0} wazuh-reinjection: {1}".format(now_date, msg) print(final_msg) if log_file: f_log.write(final_msg + "\n") EPS_MAX = 400 wazuh_path = '/var/ossec/' max_size=1 log_file = None parser = argparse.ArgumentParser(description='Reinjection script') parser.add_argument('-eps','--eps', metavar='eps', type=int, required = False, help='Events per second.') parser.add_argument('-min', '--min_timestamp', metavar='min_timestamp', type=str, required = True, help='Min timestamp. Example: 2017-12-13T23:59:06') parser.add_argument('-max', '--max_timestamp', metavar='max_timestamp', type=str, required = True, help='Max timestamp. Example: 2017-12-13T23:59:06') parser.add_argument('-o', '--output_file', metavar='output_file', type=str, required = True, help='Output filename.') parser.add_argument('-log', '--log_file', metavar='log_file', type=str, required = False, help='Logs output') parser.add_argument('-w', '--wazuh_path', metavar='wazuh_path', type=str, required = False, help='Path to Wazuh. By default:/var/ossec/') parser.add_argument('-sz', '--max_size', metavar='max_size', type=float, required = False, help='Max output file size in Gb. Default: 1Gb. Example: 2.5') args = parser.parse_args() if args.log_file: log_file = args.log_file f_log = open(log_file, 'a+') if args.max_size: max_size = args.max_size if args.wazuh_path: wazuh_path = args.wazuh_path output_file = args.output_file #Gb to bytes max_bytes = int(max_size * 1024 * 1024 * 1024) if (max_bytes <= 0): log("Error: Incorrect max_size") exit(1) month_dict = ['Null','Jan','Feb','Mar','Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov','Dec'] if args.eps: EPS_MAX = args.eps if EPS_MAX < 0: log("Error: incorrect EPS") exit(1) min_date = re.search('(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)T\\d\\d:\\d\\d:\\d\\d', args.min_timestamp) if min_date: min_year = int(min_date.group(1)) min_month = int(min_date.group(2)) min_day = int(min_date.group(3)) else: log("Error: Incorrect min timestamp") exit(1) max_date = re.search('(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)T\\d\\d:\\d\\d:\\d\\d', args.max_timestamp) if max_date: max_year = int(max_date.group(1)) max_month = int(max_date.group(2)) max_day = int(max_date.group(3)) else: log("Error: Incorrect max timestamp") exit(1) # Converting timestamp args to datetime min_timestamp = datetime.strptime(args.min_timestamp, '%Y-%m-%dT%H:%M:%S') max_timestamp = datetime.strptime(args.max_timestamp, '%Y-%m-%dT%H:%M:%S') chunk = 0 written_alerts = 0 trimmed_alerts = open(output_file, 'w') max_time=datetime(max_year, max_month, max_day) current_time=datetime(min_year, min_month, min_day) while current_time <= max_time: alert_file = "{0}logs/alerts/{1}/{2}/ossec-alerts-{3:02}.json.gz".format(wazuh_path,current_time.year,month_dict[current_time.month],current_time.day) if os.path.exists(alert_file): daily_alerts = 0 compressed_alerts = gzip.open(alert_file, 'r') log("Reading file: "+ alert_file) for line in compressed_alerts: # Transform line to json object try: line_json = json.loads(line.decode("utf-8", "replace")) # Remove unnecessary part of the timestamp string_timestamp = line_json['timestamp'][:19] # Ensure timestamp integrity while len(line_json['timestamp'].split("+")[0]) < 23: line_json['timestamp'] = line_json['timestamp'][:20] + "0" + line_json['timestamp'][20:] # Get the timestamp readable event_date = datetime.strptime(string_timestamp, '%Y-%m-%dT%H:%M:%S') # Check the timestamp belongs to the selected range if (event_date <= max_timestamp and event_date >= min_timestamp): chunk+=1 trimmed_alerts.write(json.dumps(line_json)) trimmed_alerts.write("\n") trimmed_alerts.flush() daily_alerts += 1 if chunk >= EPS_MAX: chunk = 0 time.sleep(2) if os.path.getsize(output_file) >= max_bytes: trimmed_alerts.close() log("Output file reached max size, setting it to zero and restarting") time.sleep(EPS_MAX/100) trimmed_alerts = open(output_file, 'w') except ValueError as e: print("Oops! Something went wrong reading: {}".format(line)) print("This is the error: {}".format(str(e))) compressed_alerts.close() log("Extracted {0} alerts from day {1}-{2}-{3}".format(daily_alerts,current_time.day,month_dict[current_time.month],current_time.year)) else: log("Couldn't find file {}".format(alert_file)) #Move to next file current_time += timedelta(days=1) trimmed_alerts.close()
While you run the
recovery.py
script, you need to consider the following parameters:usage: recovery.py [-h] [-eps eps] -min min_timestamp -max max_timestamp -o output_file [-log log_file] [-w wazuh_path] [-sz max_size] -eps eps, --eps eps Events per second. Default: 400 -min min_timestamp, --min_timestamp min_timestamp Min timestamp. Example: 2019-11-13T08:42:17 -max max_timestamp, --max_timestamp max_timestamp Max timestamp. Example: 2019-11-13T23:59:06 -o output_file, --output_file output_file Alerts output file. -log log_file, --log_file log_file Logs output. -w wazuh_path, --wazuh_path wazuh_path Path to Wazuh. By default:/var/ossec/ -sz max_size, --max_size max_size Max output file size in Gb. Default: 1Gb. Example: 2.5
Run the command below to make the
recovery.py
script executable:# chmod +x recovery.py
Execute the script using
nohup
command in the background to keep it running after the session is closed. It may take time depending on the size of the old logs.Usage example:
# nohup ./recovery.py -eps 500 -min 2023-06-10T00:00:00 -max 2023-06-18T23:59:59 -o /tmp/recovery.json -log ./recovery.log -sz 2.5 &
Add the
/tmp/recovery.json
path to the ThreatLockDown Filebeat module/usr/share/filebeat/module/wazuh/alerts/manifest.yml
so that Filebeat sends the old alerts to the ThreatLockDown indexer for indexing:module_version: 0.1 var: - name: paths default: - /var/ossec/logs/alerts/alerts.json - /tmp/recovery.json - name: index_prefix default: wazuh-alerts-4.x- input: config/alerts.yml ingest_pipeline: ingest/pipeline.json
Restart Filebeat for the changes to take effect.
# systemctl restart filebeat
Verifying data restoration
Using the ThreatLockDown dashboard, navigate to the Threat Hunting, File Integrity Monitoring, Vulnerability Detection, and any other modules to see if the data is restored successfully.