diff --git a/.env b/.env index 956ce40..be7ea5c 100755 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -DISCORD_WEBHOOK=https://discord.com/api/webhooks/1233074098939232286/zc-9n4LsTxSSMjg3aSUmvvAfne1Jqs-IqOA6G4ZUi1zluvmK2NOmCaO1u8KjaQ1PovVB +DISCORD_WEBHOOK=https://discord.com/api/webhooks/1235943329854783530/lgAd6On2gtLPCAZ0HABXCJvVFut7zTL0eGwYs7akkSQ7LEZA2hGtqKYag5vXMdBXJv6L diff --git a/README.md b/README.md index 48cdce8..acbb0bc 100644 --- a/README.md +++ b/README.md @@ -1 +1,25 @@ -placeholder +Wazuh notifier + +Wazuh notifier enables the Wazuh user to be notified when selected events occur. +It combines a customized custom-ar Python script ( +ref: https://documentation.wazuh.com/current/user-manual/capabilities/active-response/custom-active-response-scripts.html) +with two notifier Python scripts: a Discord notifier and a NTFY.sh notifier. + +It is a Stateless implementation and only notifies, using any or both of the messaging services. + +The ossec.conf configuration needs to include the following command and active-response configuration: + + +linux-custom-ar +custom-ar.py +yes + + + + no + linux-custom-ar + local + 503 + 60 + + diff --git a/custom-active-response.py b/custom-active-response.py index 843d010..cf9b80a 100755 --- a/custom-active-response.py +++ b/custom-active-response.py @@ -131,23 +131,33 @@ def parameters_deconstruct(event_keys): e_id: str = str(event_keys["rule"]["id"]) e_fired_times: str = str(event_keys["rule"]["firedtimes"]) - return a_id, a_name, e_id, e_description, e_level, e_fired_times + e_full_event: str = str(json.dumps(event_keys, indent=0).replace('"', '') + .replace('{', '') + .replace('}', '') + .replace('[', '') + .replace(']', '') + .replace(',', '') + .replace(' ', '') + ) + + return a_id, a_name, e_id, e_description, e_level, e_fired_times, e_full_event -def construct_message(caller: str, a_id: str, a_name: str, e_id: str, e_description: str, e_level: str, - e_fired_times: str): - discord_accent = "" - if caller == "discord": - discord_accent = "**" +def construct_basic_message(accent: str, a_id: str, a_name: str, e_id: str, e_description: str, e_level: str, + e_fired_times: str): + # Adding the BOLD text string to the Discord message. Ntfy has a different message format. - message_params: str = ("--message " + '"' + - discord_accent + "Agent: " + discord_accent + a_name + " (" + a_id + ")" + "\n" + - discord_accent + "Event id: " + discord_accent + e_id + "\n" + - discord_accent + "Description: " + discord_accent + e_description + "\n" + - discord_accent + "Threat level: " + discord_accent + e_level + "\n" + - discord_accent + "Times fired: " + discord_accent + e_fired_times + "\n" + '"') + basic_message: str = ("--message " + '"' + + accent + "Agent: " + accent + a_name + " (" + a_id + ")" + "\n" + + accent + "Event id: " + accent + e_id + "\n" + + accent + "Description: " + accent + e_description + "\n" + + accent + "Threat level: " + accent + e_level + "\n" + + # Watch this last addition to the string. It should include the closing quote for the + # basic_message string. It must be closed by -> '"'. This will be done outside this function + # in order to enable another specific addition (event_full_message) in the calling procedure. + accent + "Times fired: " + accent + e_fired_times + "\n") - return message_params + return basic_message def main(argv): @@ -168,8 +178,8 @@ def main(argv): alert = msg.alert["parameters"]["alert"] keys = [alert["rule"]] - agent_id, agent_name, event_level, event_description, event_id, event_fired_times = parameters_deconstruct( - alert) + agent_id, agent_name, event_level, event_description, event_id, event_fired_times, event_full_message = \ + parameters_deconstruct(alert) action = send_keys_and_check_message(argv, keys) @@ -186,23 +196,36 @@ def main(argv): """ Start Custom Action Add """ if str(ic("discord_enabled")) == "1": - caller = "discord" + + accent = "**" discord_notifier = '{0}/active-response/bin/wazuh-discord-notifier.py'.format(wazuh_path) discord_exec = "python3 " + discord_notifier + " " write_debug_file(argv[0], "Start Discord notifier") - discord_params = construct_message(caller, agent_id, agent_name, event_level, event_description, event_id, - event_fired_times) - discord_command = discord_exec + discord_params + discord_message = construct_basic_message(accent, agent_id, agent_name, event_level, event_description, + event_id, event_fired_times) + + if ic("discord_full_message") == "1": + discord_message = discord_message + "\n" + accent + "__Full event__" + accent + event_full_message + '"' + else: + discord_message = discord_message + '"' + discord_command = discord_exec + discord_message os.system(discord_command) if str(ic("ntfy_enabled")) == "1": - caller = "ntfy" + accent = "" ntfy_notifier = '{0}/active-response/bin/wazuh-ntfy-notifier.py'.format(wazuh_path) ntfy_exec = "python3 " + ntfy_notifier + " " write_debug_file(argv[0], "Start NTFY notifier") - ntfy_params = construct_message(caller, agent_id, agent_name, event_level, event_description, event_id, - event_fired_times) - ntfier_command = ntfy_exec + ntfy_params + ntfy_message = construct_basic_message(accent, agent_id, agent_name, event_level, event_description, + event_id, event_fired_times) + + # If the full message flag is set, the full message PLUS the closing parenthesis will be added + if ic("ntfy_full_message") == "1": + ntfy_message = ntfy_message + "\n" + "Full event" + event_full_message + '"' + else: + ntfy_message = ntfy_message + '"' + + ntfier_command = ntfy_exec + ntfy_message os.system(ntfier_command) """ End Custom Action Add """ diff --git a/wazuh-discord-notifier.py b/wazuh-discord-notifier.py index 862d136..0e0872e 100755 --- a/wazuh-discord-notifier.py +++ b/wazuh-discord-notifier.py @@ -36,13 +36,14 @@ wazuh_path, ar_path, config_path = se() now_message, now_logging = st() # Retrieve webhook from .env + +# Catching some errors try: dotenv_path = join(dirname(__file__), '.env') load_dotenv(dotenv_path) if not os.path.isfile(dotenv_path): raise Exception(dotenv_path, "file not found") discord_webhook = os.getenv("DISCORD_WEBHOOK") - except Exception as err: # output error, and return with an error code print(str(Exception(err.args))) @@ -52,13 +53,12 @@ except Exception as err: def discord_command(n_server, n_sender, n_destination, n_priority, n_message, n_tags, n_click): - x_message = (now_message + "\n\n" + n_message + "\n\n" + "Priority: " + n_priority + "\n" + "Tags: " + n_tags + "\n\n" + n_click ) - n_data = {"username": n_sender,"embeds": [{"description": x_message, "title": n_destination}]} + n_data = {"username": n_sender, "embeds": [{"description": x_message, "title": n_destination}]} result = requests.post(n_server, json=n_data) @@ -141,4 +141,3 @@ except getopt.error as err: # Finally, execute the POST request discord_command(discord_webhook, sender, destination, priority, message, tags, click) - diff --git a/wazuh-notifier-config.yaml b/wazuh-notifier-config.yaml index d29e81b..da561a3 100755 --- a/wazuh-notifier-config.yaml +++ b/wazuh-notifier-config.yaml @@ -4,13 +4,13 @@ # This is the yaml config file for both the wazuh-ntfy-notifier.py and wazuh-discord-notifier.py. # The yaml needs to be in the same folder as the wazuh-ntfy-notifier.py and wazuh-discord-notifier.py -# COMMON configuration settings start here. +# COMMON (custom-wazuh-notifiers.py) configuration settings start here. # 1 = messages will be sent through this message server. 0 = messages will NOT be sent through this message server. discord_enabled: 1 ntfy_enabled: 1 -# COMMON configuration settings start here. +# COMMON configuration settings end here. # NTFY configuration settings start here. @@ -34,7 +34,10 @@ ntfy_message: "Test message" ntfy_tags: "information, testing, yaml" ntfy_click: "https://google.com" -# NTFY configuration settings ends here. +# 1 to send the full event data with the message. 0 only sends the message with basic details +ntfy_full_message: "1" + +# NTFY configuration settings end here. # DISCORD configuration settings start here. # The default values refer to the hard-coded defaults, if no yaml configuration is found. @@ -57,6 +60,9 @@ discord_message: "Test message" discord_tags: "informational, testing, yaml" discord_click: "https://google.com" +# 1 to send the full event data with the message. 0 only sends the message with basic details +discord_full_message: "0" + # DISCORD configuration settings ends here. #end of yaml