diff --git a/html/images/appliances/GOFASTv2_back_thumb.jpg b/html/images/appliances/GOFASTv2_back_thumb.jpg
new file mode 100644
index 000000000..02751ecdc
Binary files /dev/null and b/html/images/appliances/GOFASTv2_back_thumb.jpg differ
diff --git a/html/images/appliances/GOFASTv2_front_thumb.jpg b/html/images/appliances/GOFASTv2_front_thumb.jpg
new file mode 100644
index 000000000..fd6d64b1a
Binary files /dev/null and b/html/images/appliances/GOFASTv2_front_thumb.jpg differ
diff --git a/server/modules/elastalert/elastalert.go b/server/modules/elastalert/elastalert.go
index 8d374c492..ddfd2c1be 100644
--- a/server/modules/elastalert/elastalert.go
+++ b/server/modules/elastalert/elastalert.go
@@ -83,30 +83,41 @@ var acceptedExtensions = map[string]bool{
}
type ElastAlertEngine struct {
- srv *server.Server
- airgapBasePath string
- failAfterConsecutiveErrorCount int
- sigmaPackageDownloadTemplate string
- elastAlertRulesFolder string
- rulesFingerprintFile string
- sigmaPipelineFinal string
- sigmaPipelineSO string
- sigmaPipelinesFingerprintFile string
- sigmaRulePackages []string
- autoEnabledSigmaRules []string
- additionalAlerters []string
- rulesRepos []*model.RuleRepo
- reposFolder string
- isRunning bool
- interm sync.Mutex
- airgapEnabled bool
- notify bool
- writeNoRead *string
- aiSummaries *sync.Map // map[string]*detections.AiSummary{}
- showAiSummaries bool
- aiRepoUrl string
- aiRepoBranch string
- aiRepoPath string
+ srv *server.Server
+ airgapBasePath string
+ failAfterConsecutiveErrorCount int
+ sigmaPackageDownloadTemplate string
+ elastAlertRulesFolder string
+ rulesFingerprintFile string
+ sigmaPipelineFinal string
+ sigmaPipelineSO string
+ sigmaPipelinesFingerprintFile string
+ sigmaRulePackages []string
+ autoEnabledSigmaRules []string
+ additionalAlerters []string
+ additionalAlerterParams string
+ informationalSeverityAlerters []string
+ informationalSeverityAlerterParams string
+ lowSeverityAlerters []string
+ lowSeverityAlerterParams string
+ mediumSeverityAlerters []string
+ mediumSeverityAlerterParams string
+ highSeverityAlerters []string
+ highSeverityAlerterParams string
+ criticalSeverityAlerters []string
+ criticalSeverityAlerterParams string
+ rulesRepos []*model.RuleRepo
+ reposFolder string
+ isRunning bool
+ interm sync.Mutex
+ airgapEnabled bool
+ notify bool
+ writeNoRead *string
+ aiSummaries *sync.Map // map[string]*detections.AiSummary{}
+ showAiSummaries bool
+ aiRepoUrl string
+ aiRepoBranch string
+ aiRepoPath string
detections.SyncSchedulerParams
detections.IntegrityCheckerData
detections.IOManager
@@ -167,6 +178,17 @@ func (e *ElastAlertEngine) Init(config module.ModuleConfig) (err error) {
e.CommunityRulesImportErrorSeconds = module.GetIntDefault(config, "communityRulesImportErrorSeconds", DEFAULT_COMMUNITY_RULES_IMPORT_ERROR_SECS)
e.failAfterConsecutiveErrorCount = module.GetIntDefault(config, "failAfterConsecutiveErrorCount", DEFAULT_FAIL_AFTER_CONSECUTIVE_ERROR_COUNT)
e.additionalAlerters = module.GetStringArrayDefault(config, "additionalAlerters", []string{})
+ e.additionalAlerterParams = module.GetStringDefault(config, "additionalSev0AlertersParams", "")
+ e.informationalSeverityAlerters = module.GetStringArrayDefault(config, "additionalSev1Alerters", []string{})
+ e.informationalSeverityAlerterParams = module.GetStringDefault(config, "additionalSev1AlertersParams", "")
+ e.lowSeverityAlerters = module.GetStringArrayDefault(config, "additionalSev2Alerters", []string{})
+ e.lowSeverityAlerterParams = module.GetStringDefault(config, "additionalSev2AlertersParams", "")
+ e.mediumSeverityAlerters = module.GetStringArrayDefault(config, "additionalSev3Alerters", []string{})
+ e.mediumSeverityAlerterParams = module.GetStringDefault(config, "additionalSev3AlertersParams", "")
+ e.highSeverityAlerters = module.GetStringArrayDefault(config, "additionalSev4Alerters", []string{})
+ e.highSeverityAlerterParams = module.GetStringDefault(config, "additionalSev4AlertersParams", "")
+ e.criticalSeverityAlerters = module.GetStringArrayDefault(config, "additionalSev5Alerters", []string{})
+ e.criticalSeverityAlerterParams = module.GetStringDefault(config, "additionalSev5AlertersParams", "")
e.IntegrityCheckerData.FrequencySeconds = module.GetIntDefault(config, "integrityCheckFrequencySeconds", DEFAULT_INTEGRITY_CHECK_FREQUENCY_SECONDS)
pkgs := module.GetStringArrayDefault(config, "sigmaRulePackages", []string{"core", "emerging_threats_addon"})
@@ -427,7 +449,7 @@ func (e *ElastAlertEngine) SyncLocalDetections(ctx context.Context, detections [
continue
}
- wrapped, err := wrapRule(det, eaRule, e.additionalAlerters)
+ wrapped, err := e.wrapRule(det, eaRule)
if err != nil {
continue
}
@@ -1075,7 +1097,7 @@ func (e *ElastAlertEngine) syncCommunityDetections(ctx context.Context, logger *
continue
}
- rule, err = wrapRule(detect, rule, e.additionalAlerters)
+ rule, err = e.wrapRule(detect, rule)
if err != nil {
continue
}
@@ -1508,6 +1530,64 @@ func (e *ElastAlertEngine) MergeAuxiliaryData(detect *model.Detection) error {
return nil
}
+func (e *ElastAlertEngine) getAdditionalAlerters(severity int) ([]string, string) {
+ // Start with default alerters
+ alerters := e.additionalAlerters
+ params := e.additionalAlerterParams
+
+ // Override if info or above severity
+ if severity > 0 {
+ if len(e.informationalSeverityAlerters) > 0 {
+ alerters = e.informationalSeverityAlerters
+ }
+ if len(e.informationalSeverityAlerterParams) > 0 {
+ params = e.informationalSeverityAlerterParams
+ }
+ }
+
+ // Override if low or above severity
+ if severity > 1 {
+ if len(e.lowSeverityAlerters) > 0 {
+ alerters = e.lowSeverityAlerters
+ }
+ if len(e.lowSeverityAlerterParams) > 0 {
+ params = e.lowSeverityAlerterParams
+ }
+ }
+
+ // Override if med or above severity
+ if severity > 2 {
+ if len(e.mediumSeverityAlerters) > 0 {
+ alerters = e.mediumSeverityAlerters
+ }
+ if len(e.mediumSeverityAlerterParams) > 0 {
+ params = e.mediumSeverityAlerterParams
+ }
+ }
+
+ // Override if high or crit severity
+ if severity > 3 {
+ if len(e.highSeverityAlerters) > 0 {
+ alerters = e.highSeverityAlerters
+ }
+ if len(e.highSeverityAlerterParams) > 0 {
+ params = e.highSeverityAlerterParams
+ }
+ }
+
+ // Override if crit severity
+ if severity > 4 {
+ if len(e.criticalSeverityAlerters) > 0 {
+ alerters = e.criticalSeverityAlerters
+ }
+ if len(e.criticalSeverityAlerterParams) > 0 {
+ params = e.criticalSeverityAlerterParams
+ }
+ }
+
+ return alerters, params
+}
+
type CustomWrapper struct {
DetectionTitle string `yaml:"detection_title"`
DetectionPublicId string `yaml:"detection_public_id"`
@@ -1644,7 +1724,7 @@ func (dur *TimeFrame) UnmarshalYAML(unmarshal func(interface{}) error) error {
return err
}
-func wrapRule(det *model.Detection, rule string, additionalAlerters []string) (string, error) {
+func (e *ElastAlertEngine) wrapRule(det *model.Detection, rule string) (string, error) {
severities := map[model.Severity]int{
model.SeverityUnknown: 0,
model.SeverityInformational: 1,
@@ -1654,6 +1734,13 @@ func wrapRule(det *model.Detection, rule string, additionalAlerters []string) (s
model.SeverityCritical: 5,
}
+ alerters, params := e.getAdditionalAlerters(severities[det.Severity])
+ log.WithFields(log.Fields{
+ "sevNum": severities[det.Severity],
+ "sev": det.Severity,
+ "params": params,
+ }).Error("********** Got params")
+
sevNum := severities[det.Severity]
realert := TimeFrame{}
realert.SetSeconds(0)
@@ -1678,7 +1765,7 @@ func wrapRule(det *model.Detection, rule string, additionalAlerters []string) (s
if licensing.IsEnabled(licensing.FEAT_NTF) {
// Add any custom alerters to the rule.
- for _, alerter := range additionalAlerters {
+ for _, alerter := range alerters {
alerter = strings.TrimSpace(alerter)
if len(alerter) > 0 {
wrapper.Alert = append(wrapper.Alert, alerter)
@@ -1690,8 +1777,15 @@ func wrapRule(det *model.Detection, rule string, additionalAlerters []string) (s
if err != nil {
return "", err
}
+ strYaml := string(rawYaml)
+
+ if licensing.IsEnabled(licensing.FEAT_NTF) {
+ if len(params) > 0 {
+ strYaml += "\n" + params + "\n"
+ }
+ }
- return string(rawYaml), nil
+ return strYaml, nil
}
func (e *ElastAlertEngine) IntegrityCheck(canInterrupt bool, logger *log.Entry) (deployedButNotEnabled []string, enabledButNotDeployed []string, err error) {
diff --git a/server/modules/elastalert/elastalert_test.go b/server/modules/elastalert/elastalert_test.go
index 4f852609f..1dc373098 100644
--- a/server/modules/elastalert/elastalert_test.go
+++ b/server/modules/elastalert/elastalert_test.go
@@ -339,7 +339,8 @@ func TestSigmaToElastAlertSunnyDay(t *testing.T) {
})).Return([]byte(""), 0, time.Duration(0), nil)
engine := ElastAlertEngine{
- IOManager: iom,
+ IOManager: iom,
+ additionalAlerters: []string{"email", "slack"},
}
det := &model.Detection{
@@ -362,7 +363,7 @@ func TestSigmaToElastAlertSunnyDay(t *testing.T) {
assert.NoError(t, err)
// No license
- wrappedRule, err := wrapRule(det, query, []string{"email", "slack"})
+ wrappedRule, err := engine.wrapRule(det, query)
assert.NoError(t, err)
expected := `detection_title: Test Detection
@@ -409,7 +410,9 @@ func TestSigmaToElastAlertSunnyDayLicensed(t *testing.T) {
})).Return([]byte(""), 0, time.Duration(0), nil)
engine := ElastAlertEngine{
- IOManager: iom,
+ IOManager: iom,
+ additionalAlerters: []string{"email", "slack"},
+ additionalAlerterParams: "foo: bar",
}
det := &model.Detection{
@@ -424,7 +427,7 @@ func TestSigmaToElastAlertSunnyDayLicensed(t *testing.T) {
// License
licensing.Test(licensing.FEAT_NTF, 0, 0, "", "")
- wrappedRule, err := wrapRule(det, query, []string{"email", "slack"})
+ wrappedRule, err := engine.wrapRule(det, query)
assert.NoError(t, err)
expected := `detection_title: Test Detection
@@ -444,10 +447,64 @@ realert:
seconds: 0
filter:
- eql:
+foo: bar
`
assert.YAMLEq(t, expected, wrappedRule)
}
+func TestAdditionalAlertersSev0(t *testing.T) {
+ engine := ElastAlertEngine{
+ additionalAlerters: []string{"email", "slack"},
+ additionalAlerterParams: "foo: bar",
+ }
+
+ for sev := range 6 {
+ alerters, params := engine.getAdditionalAlerters(sev)
+ assert.Equal(t, []string{"email", "slack"}, alerters)
+ assert.Equal(t, "foo: bar", params)
+ }
+}
+
+func TestAdditionalAlertersSev0Sev3(t *testing.T) {
+ engine := ElastAlertEngine{
+ additionalAlerters: []string{"email", "slack"},
+ additionalAlerterParams: "foo: bar",
+ mediumSeverityAlerters: []string{"teams"},
+ mediumSeverityAlerterParams: "foo: boo",
+ }
+
+ for sev := range 6 {
+ alerters, params := engine.getAdditionalAlerters(sev)
+ if sev < 3 {
+ assert.Equal(t, []string{"email", "slack"}, alerters)
+ assert.Equal(t, "foo: bar", params)
+ } else {
+ assert.Equal(t, []string{"teams"}, alerters)
+ assert.Equal(t, "foo: boo", params)
+ }
+ }
+}
+
+func TestAdditionalAlertersSev0Sev5(t *testing.T) {
+ engine := ElastAlertEngine{
+ additionalAlerters: []string{"email", "slack"},
+ additionalAlerterParams: "foo: bar",
+ criticalSeverityAlerters: []string{"teams"},
+ criticalSeverityAlerterParams: "foo: boo",
+ }
+
+ for sev := range 6 {
+ alerters, params := engine.getAdditionalAlerters(sev)
+ if sev < 5 {
+ assert.Equal(t, []string{"email", "slack"}, alerters)
+ assert.Equal(t, "foo: bar", params)
+ } else {
+ assert.Equal(t, []string{"teams"}, alerters)
+ assert.Equal(t, "foo: boo", params)
+ }
+ }
+}
+
func TestSigmaToElastAlertError(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()