Skip to content

Commit

Permalink
Make value comparisons case insensitive (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
bradleyjkemp authored Dec 15, 2022
1 parent 0b88725 commit bcfe96c
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 4 deletions.
85 changes: 85 additions & 0 deletions evaluator/evaluate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,88 @@ func TestRuleEvaluator_Matches_CIDR(t *testing.T) {
t.Fatal("rule should have matched")
}
}

func TestRuleEvaluator_MatchesCaseInsensitive(t *testing.T) {
rule := ForRule(sigma.Rule{
Detection: sigma.Detection{
Searches: map[string]sigma.Search{
"foo": {
EventMatchers: []sigma.EventMatcher{
{
{
Field: "foo-field",
Values: []string{
"foo-value",
},
},
},
},
},
"bar": {
EventMatchers: []sigma.EventMatcher{
{
{
Field: "bar-field",
Values: []string{
"bAr-VaLuE",
},
},
},
},
},
"baz": {
EventMatchers: []sigma.EventMatcher{
{
{
Field: "baz-field",
Values: []string{
"baz-value",
},
},
},
},
},
"null-field": {
EventMatchers: []sigma.EventMatcher{
{
{
Field: "non-existent-field",
Values: []string{
"null",
},
},
},
},
},
},
Conditions: []sigma.Condition{
{
Search: sigma.And{
sigma.SearchIdentifier{Name: "foo"},
sigma.SearchIdentifier{Name: "bar"},
sigma.SearchIdentifier{Name: "null-field"},
},
},
{
Search: sigma.AllOfThem{},
},
},
},
})

result, err := rule.Matches(context.Background(), map[string]interface{}{
"foo-field": "FoO-vAlUe",
"bar-field": "bar-value",
"baz-field": "WrOnG-vAlUe",
})
switch {
case err != nil:
t.Fatal(err)
case !result.Match:
t.Error("rule should have matched", result.SearchResults)
case !result.SearchResults["foo"] || !result.SearchResults["bar"] || result.SearchResults["baz"]:
t.Error("expected foo and bar to be true but not baz")
case !result.ConditionResults[0] || result.ConditionResults[1]:
t.Error("expected first condition to be true and second condition to be false")
}
}
11 changes: 7 additions & 4 deletions evaluator/modifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ func baseComparator(actual interface{}, expected string) bool {
// special case: "null" should match the case where a field isn't present (and so actual is nil)
return true
default:
return fmt.Sprintf("%v", actual) == expected
// The Sigma spec defines that by default comparisons are case-insensitive
return strings.EqualFold(fmt.Sprintf("%v", actual), expected)
}
}

Expand All @@ -25,17 +26,19 @@ type valueModifier func(next valueComparator) valueComparator
var modifiers = map[string]valueModifier{
"contains": func(_ valueComparator) valueComparator {
return func(actual interface{}, expected string) bool {
return strings.Contains(fmt.Sprintf("%v", actual), expected)
// The Sigma spec defines that by default comparisons are case-insensitive
return strings.Contains(strings.ToLower(fmt.Sprintf("%v", actual)), strings.ToLower(expected))
}
},
"endswith": func(_ valueComparator) valueComparator {
return func(actual interface{}, expected string) bool {
return strings.HasSuffix(fmt.Sprintf("%v", actual), expected)
// The Sigma spec defines that by default comparisons are case-insensitive
return strings.HasSuffix(strings.ToLower(fmt.Sprintf("%v", actual)), strings.ToLower(expected))
}
},
"startswith": func(_ valueComparator) valueComparator {
return func(actual interface{}, expected string) bool {
return strings.HasPrefix(fmt.Sprintf("%v", actual), expected)
return strings.HasPrefix(strings.ToLower(fmt.Sprintf("%v", actual)), strings.ToLower(expected))
}
},
"base64": func(next valueComparator) valueComparator {
Expand Down

0 comments on commit bcfe96c

Please sign in to comment.