Skip to content

Commit

Permalink
feat(rules): Introduce min-engine-version attribute (#220)
Browse files Browse the repository at this point in the history
  • Loading branch information
rabbitstack authored Dec 18, 2023
1 parent d23137b commit 9efbccc
Show file tree
Hide file tree
Showing 32 changed files with 157 additions and 11 deletions.
2 changes: 2 additions & 0 deletions pkg/config/_fixtures/filters/default-new-attributes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
rules:
- name: only network category
condition: kevt.category = 'net'
min-engine-version: 2.0.0

- group: rouge processes
rules:
- name: suspicious network {{ upper "activity" }}
condition: kevt.category = 'net' and ps.name in ('at.exe', 'java.exe')
min-engine-version: 2.0.0
2 changes: 2 additions & 0 deletions pkg/config/_fixtures/filters/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
rules:
- name: only network category
condition: kevt.category = 'net'
min-engine-version: 2.0.0

- group: rouge processes
enabled: true
rules:
- name: suspicious network {{ upper "activity" }}
condition: kevt.category = 'net' and ps.name in ('at.exe', 'java.exe')
min-engine-version: 2.0.0
1 change: 1 addition & 0 deletions pkg/config/_fixtures/filters/invalid_filter_action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
rules:
- name: suspicious network activity
condition: kevt.category = 'net' and ps.name in ('at.exe', 'java.exe')
min-engine-version: 2.0.0
action: |
{{ kil .Kevt.PID }}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
rules:
- name: suspicious network activity
condition: kevt.category = 'net' and ps.name in ('at.exe', 'java.exe')
min-engine-version: 2.0.0
action: |
{{ kill .Kevt.Pid }}
11 changes: 6 additions & 5 deletions pkg/config/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ import (

// FilterConfig is the descriptor of a single filter.
type FilterConfig struct {
Name string `json:"name" yaml:"name"`
Description string `json:"description" yaml:"description"`
Condition string `json:"condition" yaml:"condition"`
Action string `json:"action" yaml:"action"`
Labels map[string]string `json:"labels" yaml:"labels"`
Name string `json:"name" yaml:"name"`
Description string `json:"description" yaml:"description"`
Condition string `json:"condition" yaml:"condition"`
Action string `json:"action" yaml:"action"`
Labels map[string]string `json:"labels" yaml:"labels"`
MinEngineVersion string `json:"min-engine-version" yaml:"min-engine-version"`
}

// parseTmpl ensures the correctness of the rule
Expand Down
1 change: 1 addition & 0 deletions pkg/config/filters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func TestLoadGroupsFromPaths(t *testing.T) {
assert.Len(t, g1.Rules, 1)
assert.Equal(t, "only network category", g1.Rules[0].Name)
assert.Equal(t, "kevt.category = 'net'", g1.Rules[0].Condition)
assert.Equal(t, "2.0.0", g1.Rules[0].MinEngineVersion)

g2 := filters.groups[1]
assert.Equal(t, "rouge processes", g2.Name)
Expand Down
11 changes: 6 additions & 5 deletions pkg/config/schema_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,12 +489,13 @@ var rulesSchema = `
{
"type": "object",
"properties": {
"name": {"type": "string", "minLength": 3},
"description": {"type": "string"},
"condition": {"type": "string", "minLength": 3},
"action": {"type": "string"}
"name": {"type": "string", "minLength": 3},
"description": {"type": "string"},
"min-engine-version": {"type": "string", "minLength": 5, "pattern": "^([0-9]+.)([0-9]+.)([0-9]+)$"},
"condition": {"type": "string", "minLength": 3},
"action": {"type": "string"}
},
"required": ["name", "condition"],
"required": ["name", "condition", "min-engine-version"],
"minItems": 1,
"additionalProperties": false
}}},
Expand Down
18 changes: 17 additions & 1 deletion pkg/filter/_fixtures/default/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
'C:\\Windows\\system32\\wbem\\wmiprvse.exe -Embedding',
'C:\\Windows\\system32\\wbem\\wmiprvse.exe -secured -Embedding'
)
min-engine-version: 2.0.0
- name: Windows error reporting/telemetry, Search Indexer, Session Manager, Auto check utility
condition: kevt.name = 'CreateProcess' and ps.comm in
(
Expand All @@ -36,6 +37,7 @@
'\\SystemRoot\\System32\\smss.exe',
'C:\\Windows\\System32\\RuntimeBroker.exe -Embedding'
)
min-engine-version: 2.0.0
- name: Various Windows processes
condition: kevt.name = 'CreateProcess' and ps.exe in
(
Expand All @@ -62,10 +64,13 @@
'C:\\WINDOWS\\system32\\devicecensus.exe UserCxt',
'C:\\Windows\\System32\\usocoreworker.exe -Embedding'
)
min-engine-version: 2.0.0
- name: svchost
condition: kevt.name = 'CreateProcess' and ps.comm in ('svchost.exe')
min-engine-version: 2.0.0
- name: Microsoft edge
condition: kevt.name = 'CreateProcess' and ps.comm startswith '\"C:\\Program Files (x86)\\Microsoft\\Edge Dev\\Application\\msedge.exe\" --type='
min-engine-version: 2.0.0
- name: Microsoft dotNet
condition: kevt.name = 'CreateProcess' and ps.comm startswith
(
Expand All @@ -79,6 +84,7 @@
'C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\mscorsvw.exe',
'C:\\Windows\\Microsoft.Net\\Framework64\\v3.0\\WPF\\PresentationFontCache.exe'
)
min-engine-version: 2.0.0
- name: Microsoft Office
condition: kevt.name = 'CreateProcess' and ps.exe in
(
Expand All @@ -89,16 +95,19 @@
'C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\officebackgroundtaskhandler.exe',
'C:\\Program Files\\Common Files\\Microsoft Shared\\ClickToRun\\OfficeC2RClient.exe'
)
min-engine-version: 2.0.0
- name: Media Player
condition: kevt.name = 'CreateProcess' and ps.exe = 'C:\\Program Files\\Windows Media Player\\wmpnscfg.exe'
min-engine-version: 2.0.0
- name: Google
condition: kevt.name = 'CreateProcess' and ps.comm in
(
'\"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe\\\" --type='
)
min-engine-version: 2.0.0
- name: Loaded suspicious module
condition: kevt.name = 'LoadImage' and image.name = 'svchost.dll'

min-engine-version: 2.0.0

# ======================= Network connection initiated ================================
#
Expand All @@ -121,6 +130,7 @@
'C:\\Windows\\fonts',
'C:\\Windows\\system32\\config'
)
min-engine-version: 2.0.0
- name: Suspicious Windows tools network-connecting binaries
condition: kevt.name = 'Connect' and ps.name in
(
Expand Down Expand Up @@ -160,6 +170,7 @@
'wmic.exe',
'wscript.exe'
)
min-engine-version: 2.0.0
- name: Relevant 3rd Party Tools
condition: kevt.name = 'Connect' and ps.name in
(
Expand All @@ -175,6 +186,7 @@
'nmap.exe',
'psinfo.exe'
)
min-engine-version: 2.0.0
- name: Suspicious ports
condition: kevt.name = 'Connect' and net.dport in
(
Expand All @@ -193,6 +205,7 @@
9001,
9030
)
min-engine-version: 2.0.0

- group: Suspicious network-connecting binaries
enabled: true
Expand All @@ -208,7 +221,10 @@
'microsoft.com.akadns.net',
'microsoft.com.nsatc.net'
)
min-engine-version: 2.0.0
- name: OCSP protocol known addresses
condition: kevt.name = 'Connect' and net.dip in (23.4.43.27, 72.21.91.29)
min-engine-version: 2.0.0
- name: Loopback addresses
condition: kevt.name = 'Connect' and net.dip = 127.0.0.1 or net.dip startswith 'fe80:0:0:0'
min-engine-version: 2.0.0
4 changes: 4 additions & 0 deletions pkg/filter/_fixtures/merged_groups.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@
rules:
- name: match https connections
condition: kevt.name = 'Recv' and net.dport = 443
min-engine-version: 2.0.0
- name: match http connections
condition: kevt.name = 'Recv' and net.dport = 80
min-engine-version: 2.0.0

- group: network events 2
enabled: true
rules:
- name: match http connections
condition: kevt.category = 'net' and net.dport = 80
min-engine-version: 2.0.0

- group: network events 3
enabled: true
rules:
- name: match ssh connections
condition: kevt.name = 'Recv' and net.dport = 22
min-engine-version: 2.0.0
12 changes: 12 additions & 0 deletions pkg/filter/_fixtures/min-engine-ver-fail.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- group: network events
enabled: true
rules:
- name: match https connections
condition: kevt.name = 'Recv' and net.dport = 443
min-engine-version: 1.0.0
- name: accept events where source port = 44123
condition: kevt.name = 'Recv' and net.sport = 44123
min-engine-version: 2.2.0
- name: src ip address is not a loopback address
condition: kevt.name = 'Recv' and net.sip != 127.0.0.1
min-engine-version: 1.5.0
12 changes: 12 additions & 0 deletions pkg/filter/_fixtures/min-engine-ver-ok.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- group: network events
enabled: true
rules:
- name: match https connections
condition: kevt.name = 'Recv' and net.dport = 443
min-engine-version: 2.0.0
- name: accept events where source port = 44123
condition: kevt.name = 'Recv' and net.sport = 44123
min-engine-version: 1.8.0
- name: src ip address is not a loopback address
condition: kevt.name = 'Recv' and net.sip != 127.0.0.1
min-engine-version: 1.5.0
4 changes: 4 additions & 0 deletions pkg/filter/_fixtures/sequence_and_simple_rule_mix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- name: Process spawned by powershell
condition: >
kevt.name = 'CreateProcess' and ps.name = 'powershell.exe'
min-engine-version: 2.0.0
- name: Powershell created a temp file
condition: >
sequence
Expand All @@ -13,11 +14,14 @@
and
file.name icontains 'temp'
| by ps.pid
min-engine-version: 2.0.0
- name: Spawn Chrome browser
condition: >
kevt.name = 'CreateProcess' and ps.sibling.name = 'chrome.exe'
min-engine-version: 2.0.0
- name: Command shell spawned Chrome browser
condition: >
sequence maxspan 1s
|kevt.name = 'CreateProcess' and ps.name = 'powershell.exe'| by ps.pid
|kevt.name = 'CreateProcess' and ps.sibling.name = 'chrome.exe'| by ps.pid
min-engine-version: 2.0.0
1 change: 1 addition & 0 deletions pkg/filter/_fixtures/sequence_rule_bound_fields.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
$e1.ps.sid = ps.sid
| as e2
|kevt.name = 'Connect' and ps.sid != $e2.ps.sid and ps.sid = $e1.ps.sid|
min-engine-version: 2.0.0
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@
registered the password filter DLL under %2.registry.key.name registry key
`
}}
min-engine-version: 2.0.0
1 change: 1 addition & 0 deletions pkg/filter/_fixtures/sequence_rule_complex.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
"Phishing dropper outbound communication"
(printf "%s process initiated outbound communication to %s" .Kevts.k2.PS.Name .Kevts.k3.Kparams.dip)
}}
min-engine-version: 2.0.0
1 change: 1 addition & 0 deletions pkg/filter/_fixtures/sequence_rule_ps_uuid.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
and
file.extension = '.exe'
|
min-engine-version: 2.0.0
1 change: 1 addition & 0 deletions pkg/filter/_fixtures/sequence_rule_simple.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
and
file.name icontains 'temp'
| by file.name
min-engine-version: 2.0.0

1 change: 1 addition & 0 deletions pkg/filter/_fixtures/sequence_rule_simple_max_span.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
and
file.name icontains 'temp'
|
min-engine-version: 2.0.0
2 changes: 2 additions & 0 deletions pkg/filter/_fixtures/simple_emit_alert.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
action: |
{{ $text := cat .Kevt.PS.Name "process received data on port" .Kevt.Kparams.dport }}
{{ emit . "Test alert" $text "critical" "tag1" "tag2" }}
min-engine-version: 2.0.0
- name: Windows error reporting/telemetry, WMI provider host
condition: kevt.name = 'Recv' and ps.comm startswith
(
' \"C:\\Windows\\system32\\wermgr.exe\\" \"-queuereporting_svc\" ',
'C:\\Windows\\system32\\DllHost.exe /Processid'
)
min-engine-version: 2.0.0
1 change: 1 addition & 0 deletions pkg/filter/_fixtures/simple_matches.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
rules:
- name: match https connections
condition: kevt.name = 'Recv' and net.dport = 443
min-engine-version: 2.0.0
4 changes: 4 additions & 0 deletions pkg/filter/_fixtures/simple_matches_multiple_groups.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
rules:
- name: match https connections
condition: kevt.name = 'Recv' and net.dport = 443
min-engine-version: 2.0.0
- name: accept events where source port = 44123
condition: kevt.name = 'Recv' and net.sport = 44123
min-engine-version: 2.0.0
- name: src ip address is not a loopback address
condition: kevt.name = 'Recv' and net.sip != 127.0.0.1
min-engine-version: 2.0.0

- group: network events 2
enabled: true
rules:
- name: src ip address is
condition: kevt.name = 'Recv' and net.sip = 172.0.0.1
min-engine-version: 2.0.0
1 change: 1 addition & 0 deletions pkg/filter/_fixtures/simple_not_matches.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
rules:
- name: match https connections
condition: kevt.name = 'Recv' and net.sip = 172.17.0.1
min-engine-version: 2.0.0
18 changes: 18 additions & 0 deletions pkg/filter/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ import (
"github.com/rabbitstack/fibratus/pkg/ps"
"github.com/rabbitstack/fibratus/pkg/util/atomic"
"github.com/rabbitstack/fibratus/pkg/util/hashers"
"github.com/rabbitstack/fibratus/pkg/util/version"
"net"
"sort"
"strconv"
"strings"
"text/template"
"time"

semver "github.com/hashicorp/go-version"
"github.com/rabbitstack/fibratus/pkg/config"
"github.com/rabbitstack/fibratus/pkg/kevent"
log "github.com/sirupsen/logrus"
Expand All @@ -59,6 +61,12 @@ var (
ErrInvalidFilter = func(rule, group string, err error) error {
return fmt.Errorf("syntax error in rule %q located in %q group: \n%v", rule, group, err)
}
ErrIncompatibleFilter = func(rule, v string) error {
return fmt.Errorf("rule %q needs engine version [%s] but current version is [%s]", rule, v, version.Get())
}
ErrMalformedMinEngineVer = func(rule, v string, err error) error {
return fmt.Errorf("rule %q has a malformed minimum engine version: %s: %v", rule, v, err)
}
)

var (
Expand Down Expand Up @@ -490,6 +498,16 @@ func (r *Rules) Compile() error {
if err != nil {
return ErrInvalidFilter(rule.Name, group.Name, err)
}
// check version requirements
if !version.IsDev() {
minEngineVer, err := semver.NewSemver(rule.MinEngineVersion)
if err != nil {
return ErrMalformedMinEngineVer(rule.Name, rule.MinEngineVersion, err)
}
if minEngineVer.GreaterThan(version.Sem()) {
return ErrIncompatibleFilter(rule.Name, rule.MinEngineVersion)
}
}
for _, field := range f.GetFields() {
deprecated, d := fields.IsDeprecated(field)
if deprecated {
Expand Down
10 changes: 10 additions & 0 deletions pkg/filter/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package filter
import (
"github.com/rabbitstack/fibratus/pkg/fs"
"github.com/rabbitstack/fibratus/pkg/ps"
"github.com/rabbitstack/fibratus/pkg/util/version"
log "github.com/sirupsen/logrus"
"golang.org/x/sys/windows/registry"
"net"
Expand Down Expand Up @@ -266,6 +267,15 @@ func TestSequenceState(t *testing.T) {
assert.Equal(t, "kevt.name = CreateFile AND file.name ICONTAINS temp", ss.currentState())
}

func TestMinEngineVersion(t *testing.T) {
psnap := new(ps.SnapshotterMock)
rules := NewRules(psnap, newConfig("_fixtures/min-engine-ver-fail.yml"))
version.Set("2.0.0")
require.Error(t, rules.Compile())
rules = NewRules(psnap, newConfig("_fixtures/min-engine-ver-ok.yml"))
require.NoError(t, rules.Compile())
}

func TestSimpleSequenceRule(t *testing.T) {
psnap := new(ps.SnapshotterMock)
rules := NewRules(psnap, newConfig("_fixtures/sequence_rule_simple.yml"))
Expand Down
Loading

0 comments on commit 9efbccc

Please sign in to comment.