Fix overflows of overflows requesting for different decision scope (#499)
This commit is contained in:
parent
8707140fb2
commit
2e76097d35
|
@ -3,6 +3,7 @@ package csprofiles
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/antonmedv/expr"
|
"github.com/antonmedv/expr"
|
||||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||||
|
@ -45,14 +46,15 @@ func GenerateDecisionFromProfile(Profile *csconfig.ProfileCfg, Alert *models.Ale
|
||||||
decision.Value = new(string)
|
decision.Value = new(string)
|
||||||
*decision.Value = *Alert.Source.Value
|
*decision.Value = *Alert.Source.Value
|
||||||
|
|
||||||
if *decision.Scope == types.Ip {
|
if strings.EqualFold(*decision.Scope, types.Ip) {
|
||||||
srcAddr := net.ParseIP(Alert.Source.IP)
|
srcAddr := net.ParseIP(Alert.Source.IP)
|
||||||
if srcAddr == nil {
|
if srcAddr == nil {
|
||||||
return nil, fmt.Errorf("can't parse ip %s", Alert.Source.IP)
|
return nil, fmt.Errorf("can't parse ip %s", Alert.Source.IP)
|
||||||
}
|
}
|
||||||
decision.StartIP = int64(types.IP2Int(srcAddr))
|
decision.StartIP = int64(types.IP2Int(srcAddr))
|
||||||
decision.EndIP = decision.StartIP
|
decision.EndIP = decision.StartIP
|
||||||
} else if *decision.Scope == types.Range {
|
} else if strings.EqualFold(*decision.Scope, types.Range) {
|
||||||
|
|
||||||
/*here we're asked to ban a full range. let's keep in mind that it's not always possible :
|
/*here we're asked to ban a full range. let's keep in mind that it's not always possible :
|
||||||
- the alert is about an IP, but the geolite enrichment failed
|
- the alert is about an IP, but the geolite enrichment failed
|
||||||
- the alert is about an IP, but the geolite enrichment isn't present
|
- the alert is about an IP, but the geolite enrichment isn't present
|
||||||
|
@ -108,6 +110,7 @@ func EvaluateProfiles(Profiles []*csconfig.ProfileCfg, Alert *models.Alert) ([]*
|
||||||
}
|
}
|
||||||
PROFILE_LOOP:
|
PROFILE_LOOP:
|
||||||
for _, profile := range Profiles {
|
for _, profile := range Profiles {
|
||||||
|
matched := false
|
||||||
for eIdx, expression := range profile.RuntimeFilters {
|
for eIdx, expression := range profile.RuntimeFilters {
|
||||||
output, err := expr.Run(expression, exprhelpers.GetExprEnv(map[string]interface{}{"Alert": Alert}))
|
output, err := expr.Run(expression, exprhelpers.GetExprEnv(map[string]interface{}{"Alert": Alert}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -117,11 +120,13 @@ PROFILE_LOOP:
|
||||||
switch out := output.(type) {
|
switch out := output.(type) {
|
||||||
case bool:
|
case bool:
|
||||||
if out {
|
if out {
|
||||||
|
matched = true
|
||||||
/*the expression matched, create the associated decision*/
|
/*the expression matched, create the associated decision*/
|
||||||
subdecisions, err := GenerateDecisionFromProfile(profile, Alert)
|
subdecisions, err := GenerateDecisionFromProfile(profile, Alert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "while generating decision from profile %s", profile.Name)
|
return nil, errors.Wrapf(err, "while generating decision from profile %s", profile.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
decisions = append(decisions, subdecisions...)
|
decisions = append(decisions, subdecisions...)
|
||||||
} else {
|
} else {
|
||||||
if profile.Debug != nil && *profile.Debug {
|
if profile.Debug != nil && *profile.Debug {
|
||||||
|
@ -132,10 +137,14 @@ PROFILE_LOOP:
|
||||||
break PROFILE_LOOP
|
break PROFILE_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unexpected type %t (%v) while running '%s'", output, output, profile.Filters[eIdx])
|
return nil, fmt.Errorf("unexpected type %t (%v) while running '%s'", output, output, profile.Filters[eIdx])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if matched {
|
||||||
if profile.OnSuccess == "break" {
|
if profile.OnSuccess == "break" {
|
||||||
break PROFILE_LOOP
|
break PROFILE_LOOP
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,9 +115,6 @@ func (c *Client) CreateAlert(machineID string, alertList []*models.Alert) ([]str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([]string, error) {
|
func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([]string, error) {
|
||||||
var decisions []*ent.Decision
|
|
||||||
var metas []*ent.Meta
|
|
||||||
var events []*ent.Event
|
|
||||||
|
|
||||||
ret := []string{}
|
ret := []string{}
|
||||||
bulkSize := 20
|
bulkSize := 20
|
||||||
|
@ -125,6 +122,10 @@ func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([
|
||||||
c.Log.Debugf("writting %d items", len(alertList))
|
c.Log.Debugf("writting %d items", len(alertList))
|
||||||
bulk := make([]*ent.AlertCreate, 0, bulkSize)
|
bulk := make([]*ent.AlertCreate, 0, bulkSize)
|
||||||
for i, alertItem := range alertList {
|
for i, alertItem := range alertList {
|
||||||
|
var decisions []*ent.Decision
|
||||||
|
var metas []*ent.Meta
|
||||||
|
var events []*ent.Event
|
||||||
|
|
||||||
owner, err := c.QueryMachineByID(machineId)
|
owner, err := c.QueryMachineByID(machineId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Cause(err) != UserNotExists {
|
if errors.Cause(err) != UserNotExists {
|
||||||
|
@ -212,6 +213,7 @@ func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
alertB := c.Ent.Alert.
|
alertB := c.Ent.Alert.
|
||||||
Create().
|
Create().
|
||||||
SetScenario(*alertItem.Scenario).
|
SetScenario(*alertItem.Scenario).
|
||||||
|
@ -245,7 +247,7 @@ func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([
|
||||||
if len(bulk) == bulkSize {
|
if len(bulk) == bulkSize {
|
||||||
alerts, err := c.Ent.Alert.CreateBulk(bulk...).Save(c.CTX)
|
alerts, err := c.Ent.Alert.CreateBulk(bulk...).Save(c.CTX)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, errors.Wrapf(BulkError, "creating alert : %s", err)
|
return []string{}, errors.Wrapf(BulkError, "bulk creating alert : %s", err)
|
||||||
}
|
}
|
||||||
for _, alert := range alerts {
|
for _, alert := range alerts {
|
||||||
ret = append(ret, strconv.Itoa(alert.ID))
|
ret = append(ret, strconv.Itoa(alert.ID))
|
||||||
|
@ -261,7 +263,7 @@ func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([
|
||||||
|
|
||||||
alerts, err := c.Ent.Alert.CreateBulk(bulk...).Save(c.CTX)
|
alerts, err := c.Ent.Alert.CreateBulk(bulk...).Save(c.CTX)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, errors.Wrapf(BulkError, "creating alert : %s", err)
|
return []string{}, errors.Wrapf(BulkError, "leftovers creating alert : %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, alert := range alerts {
|
for _, alert := range alerts {
|
||||||
|
|
|
@ -114,7 +114,7 @@ again the expr environment given in parameter
|
||||||
*/
|
*/
|
||||||
func (e *ExprDebugger) Run(logger *logrus.Entry, filterResult bool, exprEnv map[string]interface{}) {
|
func (e *ExprDebugger) Run(logger *logrus.Entry, filterResult bool, exprEnv map[string]interface{}) {
|
||||||
if len(e.expression) == 0 {
|
if len(e.expression) == 0 {
|
||||||
logger.Debugf("no variable to eval for filter '%s'", e.filter)
|
logger.Tracef("no variable to eval for filter '%s'", e.filter)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Debugf("eval(%s) = %s", e.filter, strings.ToUpper(strconv.FormatBool(filterResult)))
|
logger.Debugf("eval(%s) = %s", e.filter, strings.ToUpper(strconv.FormatBool(filterResult)))
|
||||||
|
|
|
@ -18,12 +18,47 @@ import (
|
||||||
|
|
||||||
//SourceFromEvent extracts and formats a valid models.Source object from an Event
|
//SourceFromEvent extracts and formats a valid models.Source object from an Event
|
||||||
func SourceFromEvent(evt types.Event, leaky *Leaky) (map[string]models.Source, error) {
|
func SourceFromEvent(evt types.Event, leaky *Leaky) (map[string]models.Source, error) {
|
||||||
src := models.Source{}
|
|
||||||
srcs := make(map[string]models.Source)
|
srcs := make(map[string]models.Source)
|
||||||
|
|
||||||
|
/*if it's already an overflow, we have properly formatted sources.
|
||||||
|
we can just twitch them to reflect the requested scope*/
|
||||||
if evt.Type == types.OVFLW {
|
if evt.Type == types.OVFLW {
|
||||||
return evt.Overflow.Sources, nil
|
|
||||||
|
for k, v := range evt.Overflow.Sources {
|
||||||
|
|
||||||
|
/*the scopes are already similar, nothing to do*/
|
||||||
|
if leaky.scopeType.Scope == *v.Scope {
|
||||||
|
srcs[k] = v
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
/*The bucket requires a decision on scope Range */
|
||||||
|
if leaky.scopeType.Scope == types.Range {
|
||||||
|
/*the original bucket was target IPs, check that we do have range*/
|
||||||
|
if *v.Scope == types.Ip {
|
||||||
|
if v.Range != "" {
|
||||||
|
src := models.Source{}
|
||||||
|
src.AsName = v.AsName
|
||||||
|
src.AsNumber = v.AsNumber
|
||||||
|
src.Cn = v.Cn
|
||||||
|
src.Latitude = v.Latitude
|
||||||
|
src.Longitude = v.Longitude
|
||||||
|
src.Range = v.Range
|
||||||
|
src.Value = new(string)
|
||||||
|
src.Scope = new(string)
|
||||||
|
*src.Value = v.Range
|
||||||
|
*src.Scope = leaky.scopeType.Scope
|
||||||
|
srcs[*src.Value] = src
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warningf("bucket %s requires scope Range, but can't extrapolate from %s (%s)",
|
||||||
|
leaky.Name, *v.Scope, *v.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return srcs, nil
|
||||||
}
|
}
|
||||||
|
src := models.Source{}
|
||||||
switch leaky.scopeType.Scope {
|
switch leaky.scopeType.Scope {
|
||||||
case types.Range, types.Ip:
|
case types.Range, types.Ip:
|
||||||
if v, ok := evt.Meta["source_ip"]; ok {
|
if v, ok := evt.Meta["source_ip"]; ok {
|
||||||
|
@ -74,7 +109,7 @@ func SourceFromEvent(evt types.Event, leaky *Leaky) (map[string]models.Source, e
|
||||||
} else if leaky.scopeType.Scope == types.Range {
|
} else if leaky.scopeType.Scope == types.Range {
|
||||||
src.Value = &src.Range
|
src.Value = &src.Range
|
||||||
}
|
}
|
||||||
srcs[src.IP] = src
|
srcs[*src.Value] = src
|
||||||
default:
|
default:
|
||||||
if leaky.scopeType.RunTimeFilter != nil {
|
if leaky.scopeType.RunTimeFilter != nil {
|
||||||
retValue, err := expr.Run(leaky.scopeType.RunTimeFilter, exprhelpers.GetExprEnv(map[string]interface{}{"evt": &evt}))
|
retValue, err := expr.Run(leaky.scopeType.RunTimeFilter, exprhelpers.GetExprEnv(map[string]interface{}{"evt": &evt}))
|
||||||
|
@ -90,7 +125,6 @@ func SourceFromEvent(evt types.Event, leaky *Leaky) (map[string]models.Source, e
|
||||||
src.Scope = new(string)
|
src.Scope = new(string)
|
||||||
*src.Scope = leaky.scopeType.Scope
|
*src.Scope = leaky.scopeType.Scope
|
||||||
srcs[*src.Value] = src
|
srcs[*src.Value] = src
|
||||||
log.Debugf("source[%s] - %s = %s", leaky.Name, leaky.scopeType.Scope, *src.Value)
|
|
||||||
} else {
|
} else {
|
||||||
return srcs, fmt.Errorf("empty scope information")
|
return srcs, fmt.Errorf("empty scope information")
|
||||||
}
|
}
|
||||||
|
@ -213,7 +247,7 @@ func NewAlert(leaky *Leaky, queue *Queue) (types.RuntimeAlert, error) {
|
||||||
//Include source info in format string
|
//Include source info in format string
|
||||||
sourceStr := ""
|
sourceStr := ""
|
||||||
if len(sources) > 1 {
|
if len(sources) > 1 {
|
||||||
sourceStr = fmt.Sprintf("%d Sources on scope.", len(sources))
|
sourceStr = fmt.Sprintf("%d sources", len(sources))
|
||||||
} else if len(sources) == 1 {
|
} else if len(sources) == 1 {
|
||||||
for k, _ := range sources {
|
for k, _ := range sources {
|
||||||
sourceStr = k
|
sourceStr = k
|
||||||
|
|
|
@ -3,6 +3,8 @@ package types
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/antonmedv/expr/vm"
|
"github.com/antonmedv/expr/vm"
|
||||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||||
)
|
)
|
||||||
|
@ -38,6 +40,17 @@ type Event struct {
|
||||||
Meta map[string]string `yaml:"Meta,omitempty" json:"Meta,omitempty"`
|
Meta map[string]string `yaml:"Meta,omitempty" json:"Meta,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Event) GetType() string {
|
||||||
|
if e.Type == OVFLW {
|
||||||
|
return "overflow"
|
||||||
|
} else if e.Type == LOG {
|
||||||
|
return "log"
|
||||||
|
} else {
|
||||||
|
log.Warningf("unknown event type for %+v", e)
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Move in leakybuckets
|
//Move in leakybuckets
|
||||||
const (
|
const (
|
||||||
Undefined = ""
|
Undefined = ""
|
||||||
|
|
Loading…
Reference in a new issue