expanded fields
This commit is contained in:
parent
22bf89caf2
commit
6af3e9408a
2
.env
2
.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
|
||||||
|
|
||||||
|
|||||||
26
README.md
26
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:
|
||||||
|
<ossec_config>
|
||||||
|
<command>
|
||||||
|
<name>linux-custom-ar</name>
|
||||||
|
<executable>custom-ar.py</executable>
|
||||||
|
<timeout_allowed>yes</timeout_allowed>
|
||||||
|
</command>
|
||||||
|
|
||||||
|
<active-response>
|
||||||
|
<disabled>no</disabled>
|
||||||
|
<command>linux-custom-ar</command>
|
||||||
|
<location>local</location>
|
||||||
|
<rules_id>503</rules_id>
|
||||||
|
<timeout>60</timeout>
|
||||||
|
</active-response>
|
||||||
|
</ossec_config>
|
||||||
|
|||||||
@ -131,23 +131,33 @@ def parameters_deconstruct(event_keys):
|
|||||||
e_id: str = str(event_keys["rule"]["id"])
|
e_id: str = str(event_keys["rule"]["id"])
|
||||||
e_fired_times: str = str(event_keys["rule"]["firedtimes"])
|
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,
|
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):
|
e_fired_times: str):
|
||||||
discord_accent = ""
|
# Adding the BOLD text string to the Discord message. Ntfy has a different message format.
|
||||||
if caller == "discord":
|
|
||||||
discord_accent = "**"
|
|
||||||
|
|
||||||
message_params: str = ("--message " + '"' +
|
basic_message: str = ("--message " + '"' +
|
||||||
discord_accent + "Agent: " + discord_accent + a_name + " (" + a_id + ")" + "\n" +
|
accent + "Agent: " + accent + a_name + " (" + a_id + ")" + "\n" +
|
||||||
discord_accent + "Event id: " + discord_accent + e_id + "\n" +
|
accent + "Event id: " + accent + e_id + "\n" +
|
||||||
discord_accent + "Description: " + discord_accent + e_description + "\n" +
|
accent + "Description: " + accent + e_description + "\n" +
|
||||||
discord_accent + "Threat level: " + discord_accent + e_level + "\n" +
|
accent + "Threat level: " + accent + e_level + "\n" +
|
||||||
discord_accent + "Times fired: " + discord_accent + e_fired_times + "\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):
|
def main(argv):
|
||||||
@ -168,8 +178,8 @@ def main(argv):
|
|||||||
alert = msg.alert["parameters"]["alert"]
|
alert = msg.alert["parameters"]["alert"]
|
||||||
keys = [alert["rule"]]
|
keys = [alert["rule"]]
|
||||||
|
|
||||||
agent_id, agent_name, event_level, event_description, event_id, event_fired_times = parameters_deconstruct(
|
agent_id, agent_name, event_level, event_description, event_id, event_fired_times, event_full_message = \
|
||||||
alert)
|
parameters_deconstruct(alert)
|
||||||
|
|
||||||
action = send_keys_and_check_message(argv, keys)
|
action = send_keys_and_check_message(argv, keys)
|
||||||
|
|
||||||
@ -186,23 +196,36 @@ def main(argv):
|
|||||||
""" Start Custom Action Add """
|
""" Start Custom Action Add """
|
||||||
|
|
||||||
if str(ic("discord_enabled")) == "1":
|
if str(ic("discord_enabled")) == "1":
|
||||||
caller = "discord"
|
|
||||||
|
accent = "**"
|
||||||
discord_notifier = '{0}/active-response/bin/wazuh-discord-notifier.py'.format(wazuh_path)
|
discord_notifier = '{0}/active-response/bin/wazuh-discord-notifier.py'.format(wazuh_path)
|
||||||
discord_exec = "python3 " + discord_notifier + " "
|
discord_exec = "python3 " + discord_notifier + " "
|
||||||
write_debug_file(argv[0], "Start 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,
|
discord_message = construct_basic_message(accent, agent_id, agent_name, event_level, event_description,
|
||||||
event_fired_times)
|
event_id, event_fired_times)
|
||||||
discord_command = discord_exec + discord_params
|
|
||||||
|
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)
|
os.system(discord_command)
|
||||||
|
|
||||||
if str(ic("ntfy_enabled")) == "1":
|
if str(ic("ntfy_enabled")) == "1":
|
||||||
caller = "ntfy"
|
accent = ""
|
||||||
ntfy_notifier = '{0}/active-response/bin/wazuh-ntfy-notifier.py'.format(wazuh_path)
|
ntfy_notifier = '{0}/active-response/bin/wazuh-ntfy-notifier.py'.format(wazuh_path)
|
||||||
ntfy_exec = "python3 " + ntfy_notifier + " "
|
ntfy_exec = "python3 " + ntfy_notifier + " "
|
||||||
write_debug_file(argv[0], "Start 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,
|
ntfy_message = construct_basic_message(accent, agent_id, agent_name, event_level, event_description,
|
||||||
event_fired_times)
|
event_id, event_fired_times)
|
||||||
ntfier_command = ntfy_exec + ntfy_params
|
|
||||||
|
# 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)
|
os.system(ntfier_command)
|
||||||
|
|
||||||
""" End Custom Action Add """
|
""" End Custom Action Add """
|
||||||
|
|||||||
@ -36,13 +36,14 @@ wazuh_path, ar_path, config_path = se()
|
|||||||
now_message, now_logging = st()
|
now_message, now_logging = st()
|
||||||
|
|
||||||
# Retrieve webhook from .env
|
# Retrieve webhook from .env
|
||||||
|
|
||||||
|
# Catching some errors
|
||||||
try:
|
try:
|
||||||
dotenv_path = join(dirname(__file__), '.env')
|
dotenv_path = join(dirname(__file__), '.env')
|
||||||
load_dotenv(dotenv_path)
|
load_dotenv(dotenv_path)
|
||||||
if not os.path.isfile(dotenv_path): raise Exception(dotenv_path, "file not found")
|
if not os.path.isfile(dotenv_path): raise Exception(dotenv_path, "file not found")
|
||||||
discord_webhook = os.getenv("DISCORD_WEBHOOK")
|
discord_webhook = os.getenv("DISCORD_WEBHOOK")
|
||||||
|
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
# output error, and return with an error code
|
# output error, and return with an error code
|
||||||
print(str(Exception(err.args)))
|
print(str(Exception(err.args)))
|
||||||
@ -52,7 +53,6 @@ except Exception as err:
|
|||||||
|
|
||||||
|
|
||||||
def discord_command(n_server, n_sender, n_destination, n_priority, n_message, n_tags, n_click):
|
def discord_command(n_server, n_sender, n_destination, n_priority, n_message, n_tags, n_click):
|
||||||
|
|
||||||
x_message = (now_message +
|
x_message = (now_message +
|
||||||
"\n\n" + n_message + "\n\n" +
|
"\n\n" + n_message + "\n\n" +
|
||||||
"Priority: " + n_priority + "\n" +
|
"Priority: " + n_priority + "\n" +
|
||||||
@ -141,4 +141,3 @@ except getopt.error as err:
|
|||||||
|
|
||||||
# Finally, execute the POST request
|
# Finally, execute the POST request
|
||||||
discord_command(discord_webhook, sender, destination, priority, message, tags, click)
|
discord_command(discord_webhook, sender, destination, priority, message, tags, click)
|
||||||
|
|
||||||
|
|||||||
@ -4,13 +4,13 @@
|
|||||||
# This is the yaml config file for both the wazuh-ntfy-notifier.py and wazuh-discord-notifier.py.
|
# 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
|
# 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.
|
# 1 = messages will be sent through this message server. 0 = messages will NOT be sent through this message server.
|
||||||
|
|
||||||
discord_enabled: 1
|
discord_enabled: 1
|
||||||
ntfy_enabled: 1
|
ntfy_enabled: 1
|
||||||
|
|
||||||
# COMMON configuration settings start here.
|
# COMMON configuration settings end here.
|
||||||
|
|
||||||
|
|
||||||
# NTFY configuration settings start here.
|
# NTFY configuration settings start here.
|
||||||
@ -34,7 +34,10 @@ ntfy_message: "Test message"
|
|||||||
ntfy_tags: "information, testing, yaml"
|
ntfy_tags: "information, testing, yaml"
|
||||||
ntfy_click: "https://google.com"
|
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.
|
# DISCORD configuration settings start here.
|
||||||
# The default values refer to the hard-coded defaults, if no yaml configuration is found.
|
# 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_tags: "informational, testing, yaml"
|
||||||
discord_click: "https://google.com"
|
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.
|
# DISCORD configuration settings ends here.
|
||||||
|
|
||||||
#end of yaml
|
#end of yaml
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user