Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom notify sets #624

Merged
merged 1 commit into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion server/modules/elastalert/elastalert.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ type ElastAlertEngine struct {
aiRepoUrl string
aiRepoBranch string
aiRepoPath string
moduleConfig *module.ModuleConfig
detections.SyncSchedulerParams
detections.IntegrityCheckerData
detections.IOManager
Expand Down Expand Up @@ -190,6 +191,8 @@ func (e *ElastAlertEngine) Init(config module.ModuleConfig) (err error) {
e.highSeverityAlerterParams = module.GetStringDefault(config, "additionalSev4AlertersParams", "")
e.criticalSeverityAlerters = module.GetStringArrayDefault(config, "additionalSev5Alerters", []string{})
e.criticalSeverityAlerterParams = module.GetStringDefault(config, "additionalSev5AlertersParams", "")
e.moduleConfig = &config

e.IntegrityCheckerData.FrequencySeconds = module.GetIntDefault(config, "integrityCheckFrequencySeconds", DEFAULT_INTEGRITY_CHECK_FREQUENCY_SECONDS)

pkgs := module.GetStringArrayDefault(config, "sigmaRulePackages", []string{"core", "emerging_threats_addon"})
Expand Down Expand Up @@ -1578,6 +1581,25 @@ func (e *ElastAlertEngine) MergeAuxiliaryData(detect *model.Detection) error {
return nil
}

func (e *ElastAlertEngine) getCustomAlerters(tags []string) ([]string, string) {
alertersKey := ""
paramsKey := ""
if e.moduleConfig != nil {
for _, tag := range tags {
if strings.HasPrefix(tag, "so.alerters.") {
alertersKey = strings.TrimPrefix(tag, "so.alerters.")
}
if strings.HasPrefix(tag, "so.params.") {
paramsKey = strings.TrimPrefix(tag, "so.params.")
}
}
alerters := module.GetStringArrayDefault(*e.moduleConfig, alertersKey, []string{})
params := module.GetStringDefault(*e.moduleConfig, paramsKey, "")
return alerters, params
}
return []string{}, ""
}

func (e *ElastAlertEngine) getAdditionalAlerters(severity int) ([]string, string) {
// Start with default alerters
alerters := e.additionalAlerters
Expand Down Expand Up @@ -1782,7 +1804,10 @@ func (e *ElastAlertEngine) wrapRule(det *model.Detection, rule string) (string,
model.SeverityCritical: 5,
}

alerters, params := e.getAdditionalAlerters(severities[det.Severity])
alerters, params := e.getCustomAlerters(det.Tags)
if len(alerters) == 0 {
alerters, params = e.getAdditionalAlerters(severities[det.Severity])
}

sevNum := severities[det.Severity]
realert := TimeFrame{}
Expand Down
149 changes: 149 additions & 0 deletions server/modules/elastalert/elastalert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,155 @@ foo: bar
assert.YAMLEq(t, expected, wrappedRule)
}

func TestSigmaToElastAlertCustomNotificationLicensed(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

iom := mock.NewMockIOManager(ctrl)

iom.EXPECT().ExecCommand(gomock.Cond(func(x any) bool {
cmd := x.(*exec.Cmd)

if !strings.HasSuffix(cmd.Path, "sigma") {
return false
}

if !slices.Contains(cmd.Args, "convert") {
return false
}

if cmd.Stdin == nil {
return false
}

return true
})).Return([]byte("<eql>"), 0, time.Duration(0), nil)

config := make(module.ModuleConfig)
alerters := make([]interface{}, 0)
alerters = append(alerters, "post2")
alerters = append(alerters, "pagerduty")
config["MyAlerters"] = alerters
config["MyParams"] = "foo: car"

engine := ElastAlertEngine{
IOManager: iom,
additionalAlerters: []string{"email", "slack"},
additionalAlerterParams: "foo: bar",
moduleConfig: &config,
}

det := &model.Detection{
PublicID: "00000000-0000-0000-0000-000000000000",
Content: "totally good sigma",
Title: "Test Detection",
Tags: []string{"so.alerters.MyAlerters", "so.params.MyParams"},
Severity: model.SeverityHigh,
}

query, err := engine.sigmaToElastAlert(context.Background(), det)
assert.NoError(t, err)

// License
licensing.Test(licensing.FEAT_NTF, 0, 0, "", "")
wrappedRule, err := engine.wrapRule(det, query)
assert.NoError(t, err)

expected := `detection_title: Test Detection
detection_public_id: 00000000-0000-0000-0000-000000000000
event.module: sigma
event.dataset: sigma.alert
event.severity: 4
sigma_level: high
alert:
- modules.so.securityonion-es.SecurityOnionESAlerter
- post2
- pagerduty
index: .ds-logs-*
name: Test Detection -- 00000000-0000-0000-0000-000000000000
type: any
realert:
seconds: 0
filter:
- eql: <eql>
foo: car
`
assert.YAMLEq(t, expected, wrappedRule)
}

func TestSigmaToElastAlertCustomNotificationUnlicensed(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

iom := mock.NewMockIOManager(ctrl)

iom.EXPECT().ExecCommand(gomock.Cond(func(x any) bool {
cmd := x.(*exec.Cmd)

if !strings.HasSuffix(cmd.Path, "sigma") {
return false
}

if !slices.Contains(cmd.Args, "convert") {
return false
}

if cmd.Stdin == nil {
return false
}

return true
})).Return([]byte("<eql>"), 0, time.Duration(0), nil)

config := make(module.ModuleConfig)
alerters := make([]interface{}, 0)
alerters = append(alerters, "post2")
alerters = append(alerters, "pagerduty")
config["MyAlerters"] = alerters
config["MyParams"] = "foo: car"

engine := ElastAlertEngine{
IOManager: iom,
additionalAlerters: []string{"email", "slack"},
additionalAlerterParams: "foo: bar",
moduleConfig: &config,
}

det := &model.Detection{
PublicID: "00000000-0000-0000-0000-000000000000",
Content: "totally good sigma",
Title: "Test Detection",
Tags: []string{"so.alerters.MyAlerters", "so.params.MyParams"},
Severity: model.SeverityHigh,
}

query, err := engine.sigmaToElastAlert(context.Background(), det)
assert.NoError(t, err)

// License
licensing.Shutdown()
wrappedRule, err := engine.wrapRule(det, query)
assert.NoError(t, err)

expected := `detection_title: Test Detection
detection_public_id: 00000000-0000-0000-0000-000000000000
event.module: sigma
event.dataset: sigma.alert
event.severity: 4
sigma_level: high
alert:
- modules.so.securityonion-es.SecurityOnionESAlerter
index: .ds-logs-*
name: Test Detection -- 00000000-0000-0000-0000-000000000000
type: any
realert:
seconds: 0
filter:
- eql: <eql>
`
assert.YAMLEq(t, expected, wrappedRule)
}

func TestSigmaToElastAlertNotificationOnlyLicensed(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Expand Down
Loading