diff --git a/test.go b/test.go new file mode 100644 index 0000000..7bfc947 --- /dev/null +++ b/test.go @@ -0,0 +1,11 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + fmt.Println("hier") + os.Stderr.Write([]byte("hier2")) +} diff --git a/wazuh-notifier-conf.yaml b/wazuh-notifier-conf.yaml new file mode 100755 index 0000000..2fbe808 --- /dev/null +++ b/wazuh-notifier-conf.yaml @@ -0,0 +1,31 @@ +--- +#start of yaml + +# 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 (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. + +targets: "discord,ntfy" + +# Exclude rules that are listed in the ossec.conf active response definition. + +excluded_rules: "5401, 5403" +excluded_agents: "999" + +# Priority mapping from 1-12 (Wazuh events) to 1-5 (Discord and ntfy notification) + +notifier_priority_1: 12, 11, 10 +notifier_priority_2: 9, 8 +notifier_priority_3: 7, 6 +notifier_priority_4: 5, 4 +notifier_priority_5: 3 ,2, 1 + +sender: "Wazuh (IDS)" +click: "https://google.com" + + +#end of yaml +... + diff --git a/wazuh-notify-go/config.yaml b/wazuh-notify-go/config.yaml index 1f9c60c..50a3302 100644 --- a/wazuh-notify-go/config.yaml +++ b/wazuh-notify-go/config.yaml @@ -16,11 +16,11 @@ excluded_agents: "999" # Priority mapping from 1-12 (Wazuh events) to 1-5 (Discord and ntfy notification) -notifier_priority_1: 12, 11, 10 -notifier_priority_2: 9, 8 -notifier_priority_3: 7, 6 -notifier_priority_4: 5, 4 -notifier_priority_5: 3 ,2, 1 +priority_1: 12, 11, 10 +priority_2: 9, 8 +priority_3: 7, 6 +priority_4: 5, 4 +priority_5: 3 ,2, 1 sender: "Wazuh (IDS)" click: "https://google.com" diff --git a/wazuh-notify-go/log/log.go b/wazuh-notify-go/log/log.go new file mode 100644 index 0000000..4864f5a --- /dev/null +++ b/wazuh-notify-go/log/log.go @@ -0,0 +1,14 @@ +package log + +import ( + "os" + "time" +) + +var f, _ = os.OpenFile("active-responses.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + +func Log(message string) { + if _, err := f.WriteString("\n" + time.Now().Format(time.DateTime) + message); err != nil { + panic(err) + } +} diff --git a/wazuh-notify-go/main.go b/wazuh-notify-go/main.go index 42685c9..807af23 100644 --- a/wazuh-notify-go/main.go +++ b/wazuh-notify-go/main.go @@ -2,19 +2,21 @@ package main import ( "strings" + "wazuh-notify/log" "wazuh-notify/notification" - "wazuh-notify/types" + "wazuh-notify/services" ) -var inputParams types.Params - func main() { - initNotify() + inputParams := services.InitNotify() + for _, target := range strings.Split(inputParams.Targets, ",") { switch target { case "discord": + log.Log(target) notification.SendDiscord(inputParams) case "ntfy": + log.Log(target) notification.SendNtfy(inputParams) } } diff --git a/wazuh-notify-go/notification/discord.go b/wazuh-notify-go/notification/discord.go index 6c625c5..1c89b41 100644 --- a/wazuh-notify-go/notification/discord.go +++ b/wazuh-notify-go/notification/discord.go @@ -3,26 +3,30 @@ package notification import ( "bytes" "encoding/json" - "fmt" "log" "net/http" "os" + "strconv" "wazuh-notify/types" ) func SendDiscord(params types.Params) { - embedDescription := fmt.Sprintf("\n\n %s \n\nPriority: %x\nTags: %s\n\n%s", - params.Message, - params.Priority, - params.Tags, - params.Click, - ) + embedDescription := "\n\n" + + "**Agent:** " + params.WazuhMessage.Parameters.Alert.Agent.Name + "\n" + + "**Event id:** " + params.WazuhMessage.Parameters.Alert.Rule.ID + "\n" + + "**Description:** " + params.WazuhMessage.Parameters.Alert.Rule.Description + "\n" + + "**Threat level:** " + strconv.Itoa(params.WazuhMessage.Parameters.Alert.Rule.Level) + "\n" + + "**Times fired:** " + strconv.Itoa(params.WazuhMessage.Parameters.Alert.Rule.Firedtimes) + + "\n\n" + + "Priority: " + strconv.Itoa(params.Priority) + "\n" + + "Tags: " + params.Tags + "\n\n" + + params.Click message := types.Message{ Username: params.Sender, Embeds: []types.Embed{ { - Title: params.Destination, + Title: params.Sender, Description: embedDescription, }, }, diff --git a/wazuh-notify-go/notification/ntfy.go b/wazuh-notify-go/notification/ntfy.go index 3749d41..995a102 100644 --- a/wazuh-notify-go/notification/ntfy.go +++ b/wazuh-notify-go/notification/ntfy.go @@ -11,7 +11,12 @@ import ( func SendNtfy(params types.Params) { - payload := time.Now().Format(time.RFC3339) + "\n\n" + params.Message + payload := time.Now().Format(time.RFC3339) + "\n\n" + + "Agent: " + params.WazuhMessage.Parameters.Alert.Agent.Name + "\n" + + "Event id: " + params.WazuhMessage.Parameters.Alert.Rule.ID + "\n" + + "Description: " + params.WazuhMessage.Parameters.Alert.Rule.Description + "\n" + + "Threat level: " + strconv.Itoa(params.WazuhMessage.Parameters.Alert.Rule.Level) + "\n" + + "Times fired: " + strconv.Itoa(params.WazuhMessage.Parameters.Alert.Rule.Firedtimes) + "\n" req, _ := http.NewRequest("POST", os.Getenv("NTFY_URL"), strings.NewReader(payload)) req.Header.Set("Content-Type", "text/plain") diff --git a/wazuh-notify-go/init.go b/wazuh-notify-go/services/init.go similarity index 63% rename from wazuh-notify-go/init.go rename to wazuh-notify-go/services/init.go index 3d1a4f6..2f8cdb8 100644 --- a/wazuh-notify-go/init.go +++ b/wazuh-notify-go/services/init.go @@ -1,34 +1,56 @@ -package main +package services import ( + "bufio" + "encoding/json" "flag" "github.com/joho/godotenv" "gopkg.in/yaml.v2" - "log" "os" + "wazuh-notify/log" "wazuh-notify/types" ) +var inputParams types.Params var configParams types.Params +var wazuhData types.WazuhMessage -func initNotify() { +func InitNotify() types.Params { err := godotenv.Load() if err != nil { - log.Fatalf(".env not found: %v", err) - return + log.Log("env failed to load") + } else { + log.Log("env loaded") } + wazuhInput() + yamlFile, err := os.ReadFile("./config.yaml") yaml.Unmarshal(yamlFile, &configParams) - flag.StringVar(&inputParams.Server, "server", "", "is the webhook URL of the Discord server. It is stored in .env.") + log.Log("yaml loaded") + + flag.StringVar(&inputParams.Url, "url", "", "is the webhook URL of the Discord server. It is stored in .env.") flag.StringVar(&inputParams.Click, "click", configParams.Click, "is a link (URL) that can be followed by tapping/clicking inside the message. Default is https://google.com.") - flag.StringVar(&inputParams.Destination, "destination", "", "is the destination (actually the originator) of the message, either an app name or a person. Default is \"Wazuh (IDS)\"") - flag.StringVar(&inputParams.Message, "message", "", "is the text of the message to be sent. Default is \"Test message\", but may include --tags and/or --click.") flag.IntVar(&inputParams.Priority, "priority", 0, "is the priority of the message, ranging from 1 (highest), to 5 (lowest). Default is 5.") flag.StringVar(&inputParams.Sender, "sender", configParams.Sender, "is the sender of the message, either an app name or a person. The default is \"Security message\".") flag.StringVar(&inputParams.Tags, "tags", "", "is an arbitrary strings of tags (keywords), seperated by a \",\" (comma). Default is \"informational,testing,hard-coded\".") flag.StringVar(&inputParams.Targets, "targets", "", "is a list of targets to send notifications to. Default is \"discord\".") flag.Parse() + + log.Log("yaml loaded") + inputParams.Targets = configParams.Targets + + return inputParams +} + +func wazuhInput() { + reader := bufio.NewReader(os.Stdin) + + json.NewDecoder(reader).Decode(&wazuhData) + + mapPriority() + + inputParams.WazuhMessage = wazuhData } diff --git a/wazuh-notify-go/services/mapping.go b/wazuh-notify-go/services/mapping.go new file mode 100644 index 0000000..90a1219 --- /dev/null +++ b/wazuh-notify-go/services/mapping.go @@ -0,0 +1,21 @@ +package services + +import "slices" + +func mapPriority() { + if slices.Contains(configParams.Priority1, wazuhData.Parameters.Alert.Rule.Level) { + inputParams.Priority = wazuhData.Parameters.Alert.Rule.Level + } + if slices.Contains(configParams.Priority2, wazuhData.Parameters.Alert.Rule.Level) { + inputParams.Priority = wazuhData.Parameters.Alert.Rule.Level + } + if slices.Contains(configParams.Priority3, wazuhData.Parameters.Alert.Rule.Level) { + inputParams.Priority = wazuhData.Parameters.Alert.Rule.Level + } + if slices.Contains(configParams.Priority4, wazuhData.Parameters.Alert.Rule.Level) { + inputParams.Priority = wazuhData.Parameters.Alert.Rule.Level + } + if slices.Contains(configParams.Priority5, wazuhData.Parameters.Alert.Rule.Level) { + inputParams.Priority = wazuhData.Parameters.Alert.Rule.Level + } +} diff --git a/wazuh-notify-go/types/types.go b/wazuh-notify-go/types/types.go index 7c2ac96..cb2970c 100644 --- a/wazuh-notify-go/types/types.go +++ b/wazuh-notify-go/types/types.go @@ -1,14 +1,18 @@ package types type Params struct { - Server string - Sender string `yaml:"sender,omitempty"` - Destination string - Priority int - Message string - Tags string - Click string `yaml:"click,omitempty"` - Targets string `yaml:"targets,omitempty"` + Url string + Sender string `yaml:"sender,omitempty"` + Priority int + Tags string + Click string `yaml:"click,omitempty"` + Targets string `yaml:"targets,omitempty"` + WazuhMessage WazuhMessage + Priority1 []int `yaml:"priority_1"` + Priority2 []int `yaml:"priority_2"` + Priority3 []int `yaml:"priority_3"` + Priority4 []int `yaml:"priority_4"` + Priority5 []int `yaml:"priority_5"` } type Message struct { diff --git a/wazuh-notify-go/types/wazuh.go b/wazuh-notify-go/types/wazuh.go new file mode 100644 index 0000000..4a4da76 --- /dev/null +++ b/wazuh-notify-go/types/wazuh.go @@ -0,0 +1,72 @@ +package types + +type WazuhMessage struct { + Version int `json:"version"` + Origin Origin `json:"origin"` + Command string `json:"command"` + Parameters Parameters `json:"parameters"` +} + +type Origin struct { + Name string `json:"name"` + Module string `json:"module"` +} + +type Parameters struct { + ExtraArgs []interface{} `json:"extra_args"` + Alert Alert `json:"alert"` + Program string `json:"program"` +} + +type Alert struct { + Timestamp string `json:"timestamp"` + Rule Rule `json:"rule"` + Agent Agent `json:"agent"` + Manager Manager `json:"manager"` + ID string `json:"id"` + FullLog string `json:"full_log"` + Decoder Decoder `json:"decoder"` + Data Data `json:"data"` + Location string `json:"location"` +} + +type Rule struct { + Level int `json:"level"` + Description string `json:"description"` + ID string `json:"id"` + Mitre Mitre `json:"mitre"` + Info string `json:"info"` + Firedtimes int `json:"firedtimes"` + Mail bool `json:"mail"` + Groups []string `json:"groups"` + PciDss []string `json:"pci_dss"` + Gdpr []string `json:"gdpr"` + Nist80053 []string `json:"nist_800_53"` + Tsc []string `json:"tsc"` +} + +type Mitre struct { + ID []string `json:"id"` + Tactic []string `json:"tactic"` + Technique []string `json:"technique"` +} + +type Agent struct { + ID string `json:"id"` + Name string `json:"name"` +} + +type Manager struct { + Name string `json:"name"` +} + +type Decoder struct { + Name string `json:"name"` +} + +type Data struct { + Protocol string `json:"protocol"` + Srcip string `json:"srcip"` + ID string `json:"id"` + URL string `json:"url"` +} diff --git a/wazuh_notifier_module.py b/wazuh_notifier_module.py index f8f2c0f..e6de6ad 100755 --- a/wazuh_notifier_module.py +++ b/wazuh_notifier_module.py @@ -45,7 +45,7 @@ def set_environment(): wazuh_path = "/var/ossec" # wazuh_path = os.path.abspath(os.path.join(__file__, "../../..")) ar_path = '{0}/logs/active-responses.log'.format(wazuh_path) - config_path = 'wazuh-notifier-config.yaml'.format(wazuh_path) + config_path = 'wazuh-notifier-conf.yaml'.format(wazuh_path) return wazuh_path, ar_path, config_path