Skip to content

Commit

Permalink
Merge pull request #624 from Security-Onion-Solutions/jertel/an2
Browse files Browse the repository at this point in the history
custom notify sets
  • Loading branch information
jertel authored Aug 27, 2024
2 parents e8a8909 + 9f9b623 commit 6cbc897
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 1 deletion.
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

0 comments on commit 6cbc897

Please sign in to comment.