Skip to content
This repository was archived by the owner on Apr 27, 2023. It is now read-only.

Commit 82035d4

Browse files
committed
added dynamic rule engine
1 parent f982b0f commit 82035d4

File tree

8 files changed

+83
-41
lines changed

8 files changed

+83
-41
lines changed

Gopkg.lock

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/dynamic_rules.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
---
2-
- description: fetching external resources
3-
event_type: PROCESS_EVENT_TYPE_EXEC
4-
actions:
2+
-
3+
name: insider_threat
4+
description: "IT'S COMING FROM INSIDE THE HOUSE!"
5+
query: ClientAddr='127.0.0.1'
6+
actions:
57
- alert
8+
indicator_type: custom
69
score: 60
7-
query: 'exec_filename ~= (wget || curl)'

server/daemon/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func Start() {
7979
}
8080

8181
// handle connection in goroutine so we can accept new TCP connections
82-
go server.handleConn(conn, eventChan, incomingConn.RemoteAddr().String())
82+
go server.handleConn(conn, eventChan, incomingConn.RemoteAddr().(*net.TCPAddr).IP.String())
8383
}
8484
}
8585

server/engines/dynamic/dynamic.go

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,74 @@ import (
55
"log"
66
"os"
77

8+
"github.com/caibirdme/yql"
89
"github.com/dustin-decker/threatseer/server/event"
10+
"github.com/fatih/structs"
911
yaml "gopkg.in/yaml.v2"
1012
)
1113

12-
type dynamicRule struct {
13-
eventType string `yaml:"event_type"`
14-
description string `yaml:"description"`
15-
actions []string `yaml:"actions"`
16-
query string `yaml:"query"`
17-
score int `yaml:"score"`
14+
type DynamicRules []struct {
15+
Name string `yaml:"name"`
16+
Description string `yaml:"description"`
17+
EventType string `yaml:"event_type"`
18+
Query string `yaml:"query"`
19+
Actions []string `yaml:"actions"`
20+
IndicatorType string `yaml:"indicator_type"`
21+
Score int `yaml:"score"`
1822
}
1923

20-
type DynamicRulesEngine struct {
24+
// RulesEngine stores engine state
25+
type RulesEngine struct {
2126
Out chan event.Event
22-
dynamicRules []dynamicRule
27+
DynamicRules DynamicRules
2328
}
2429

2530
// Run initiates the engine on the pipeline
26-
func (engine *DynamicRulesEngine) Run(in chan event.Event) {
31+
func (engine *RulesEngine) Run(in chan event.Event) {
2732
for {
33+
// incoming event from the pipeline
2834
e := <-in
29-
// log.Print(e)
35+
36+
// convert struct to map[string]interface{}
37+
evnt := structs.Map(e)
38+
39+
for _, rule := range engine.DynamicRules {
40+
if len(rule.Query) > 0 {
41+
result, err := yql.Match(rule.Query, evnt)
42+
if err != nil {
43+
if err.Error() == "interface conversion: interface is nil, not antlr.ParserRuleContext" {
44+
log.Print("incorrect syntax for dynamic engine rule, got: ", rule.Query)
45+
} else {
46+
log.Print("dynamic engine got error while testing rule: ", err)
47+
}
48+
}
49+
if result {
50+
e.Indicators = append(
51+
e.Indicators,
52+
event.Indicator{
53+
Engine: "dynamic",
54+
IndicatorType: rule.IndicatorType,
55+
Description: rule.Description,
56+
Score: rule.Score,
57+
RuleName: rule.Name,
58+
},
59+
)
60+
}
61+
}
62+
}
63+
64+
// make event available to the next pipeline engine
3065
engine.Out <- e
3166
}
3267
}
3368

3469
// NewDynamicRulesEngine returns engine with configs loaded
35-
func NewDynamicRulesEngine() DynamicRulesEngine {
36-
var e DynamicRulesEngine
70+
func NewDynamicRulesEngine() RulesEngine {
71+
var e RulesEngine
3772

3873
// load risky_process.yaml information
3974
filename := "config/dynamic_rules.yaml"
40-
var dr []dynamicRule
75+
var dr DynamicRules
4176
if _, err := os.Stat(filename); os.IsNotExist(err) {
4277
log.Printf("%s does not exist, not loading any data for that check", filename)
4378
} else {
@@ -50,7 +85,7 @@ func NewDynamicRulesEngine() DynamicRulesEngine {
5085
log.Fatalf("could not parse %s, got %s", filename, err.Error())
5186
}
5287
}
53-
e.dynamicRules = dr
88+
e.DynamicRules = dr
5489
e.Out = make(chan event.Event, 0)
5590

5691
return e

server/engines/dynamic/query_stream_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,5 @@ func BenchmarkYQL(b *testing.B) {
3131
json.Unmarshal([]byte(jsonString), &temp)
3232

3333
yql.Match(rawYQL, temp)
34-
// result, _ := yql.Match(rawYQL, temp)
35-
// fmt.Println(result)
3634
}
3735
}

server/engines/static/risky_processes.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ type riskyProcess struct {
1717

1818
func (rp *riskyProcess) Indicator() event.Indicator {
1919
return event.Indicator{
20-
Engine: "static",
21-
Type: "risky_process",
22-
Description: fmt.Sprintf("%s is a risky process often used for %s", rp.Name, rp.Reason),
23-
Score: rp.Score,
20+
Engine: "static",
21+
IndicatorType: "risky_process",
22+
Description: fmt.Sprintf("%s is a risky process often used for %s", rp.Name, rp.Reason),
23+
Score: rp.Score,
2424
}
2525
}
2626

27-
func (engine *StaticRulesEngine) checkRiskyProcess(processInfo *api.ProcessEvent) *riskyProcess {
27+
func (engine *RulesEngine) checkRiskyProcess(processInfo *api.ProcessEvent) *riskyProcess {
2828
if processInfo != nil {
2929
cl := processInfo.GetExecFilename()
3030
for _, rp := range engine.riskyProcesses {

server/engines/static/static.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,20 @@ import (
1010
"github.com/dustin-decker/threatseer/server/event"
1111
)
1212

13-
type StaticRulesEngine struct {
13+
// RulesEngine stores engine state
14+
type RulesEngine struct {
1415
Out chan event.Event
1516
riskyProcesses []riskyProcess
1617
}
1718

1819
// Run initiates the engine on the pipeline
19-
func (engine *StaticRulesEngine) Run(in chan event.Event) {
20+
func (engine *RulesEngine) Run(in chan event.Event) {
2021
for {
22+
// incoming event from the pipeline
2123
e := <-in
2224

25+
// process checks
2326
processInfo := e.Event.GetProcess()
24-
2527
if processInfo != nil {
2628
// check for risky processes
2729
rp := engine.checkRiskyProcess(processInfo)
@@ -30,14 +32,14 @@ func (engine *StaticRulesEngine) Run(in chan event.Event) {
3032
}
3133
}
3234

33-
// log.Print(e.Event)
35+
// make event available to the next pipeline engine
3436
engine.Out <- e
3537
}
3638
}
3739

3840
// NewStaticRulesEngine returns engine with configs loaded
39-
func NewStaticRulesEngine() StaticRulesEngine {
40-
var e StaticRulesEngine
41+
func NewStaticRulesEngine() RulesEngine {
42+
var e RulesEngine
4143

4244
// load risky_process.yaml information
4345
filename := "config/risky_processes.yaml"

server/event/event.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package event
22

33
import (
4-
"net"
5-
64
api "github.com/capsule8/capsule8/api/v0"
75
)
86

@@ -12,14 +10,15 @@ import (
1210
type Event struct {
1311
Event *api.TelemetryEvent
1412
Indicators []Indicator
15-
ClientAddr net.Addr
13+
ClientAddr string
1614
}
1715

1816
// Indicator is an individual result from an engine
1917
type Indicator struct {
20-
Engine string
21-
Type string
22-
Description string
23-
ExtraInfo string
24-
Score int
18+
Engine string
19+
RuleName string
20+
IndicatorType string
21+
Description string
22+
ExtraInfo string
23+
Score int
2524
}

0 commit comments

Comments
 (0)