progress
This commit is contained in:
parent
d123254949
commit
30455a8eb6
3
go.mod
3
go.mod
|
@ -52,7 +52,7 @@ require (
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
github.com/stretchr/testify v1.8.3
|
github.com/stretchr/testify v1.8.3
|
||||||
golang.org/x/crypto v0.1.0
|
golang.org/x/crypto v0.1.0
|
||||||
golang.org/x/mod v0.6.0
|
golang.org/x/mod v0.8.0
|
||||||
google.golang.org/grpc v1.47.0
|
google.golang.org/grpc v1.47.0
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
|
@ -206,4 +206,3 @@ require (
|
||||||
replace golang.org/x/time/rate => github.com/crowdsecurity/crowdsec/pkg/time/rate v0.0.0
|
replace golang.org/x/time/rate => github.com/crowdsecurity/crowdsec/pkg/time/rate v0.0.0
|
||||||
|
|
||||||
replace github.com/corazawaf/coraza/v3 => ./coraza
|
replace github.com/corazawaf/coraza/v3 => ./coraza
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ import (
|
||||||
corazatypes "github.com/corazawaf/coraza/v3/types"
|
corazatypes "github.com/corazawaf/coraza/v3/types"
|
||||||
"github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration"
|
"github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration"
|
||||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||||
|
"github.com/crowdsecurity/go-cs-lib/pkg/trace"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
@ -144,6 +146,8 @@ func (w *WafSource) Configure(yamlConfig []byte, logger *log.Entry) error {
|
||||||
return errors.Wrap(err, "Cannot create WAF")
|
return errors.Wrap(err, "Cannot create WAF")
|
||||||
}
|
}
|
||||||
w.outOfBandWaf = outofbandwaf
|
w.outOfBandWaf = outofbandwaf
|
||||||
|
log.Printf("OOB -> %s", spew.Sdump(w.outOfBandWaf))
|
||||||
|
log.Printf("IB -> %s", spew.Sdump(w.inBandWaf))
|
||||||
|
|
||||||
//We don´t use the wrapper provided by coraza because we want to fully control what happens when a rule match to send the information in crowdsec
|
//We don´t use the wrapper provided by coraza because we want to fully control what happens when a rule match to send the information in crowdsec
|
||||||
w.mux.HandleFunc(w.config.Path, w.wafHandler)
|
w.mux.HandleFunc(w.config.Path, w.wafHandler)
|
||||||
|
@ -170,7 +174,7 @@ func (w *WafSource) OneShotAcquisition(out chan types.Event, t *tomb.Tomb) error
|
||||||
func (w *WafSource) StreamingAcquisition(out chan types.Event, t *tomb.Tomb) error {
|
func (w *WafSource) StreamingAcquisition(out chan types.Event, t *tomb.Tomb) error {
|
||||||
w.outChan = out
|
w.outChan = out
|
||||||
t.Go(func() error {
|
t.Go(func() error {
|
||||||
defer types.CatchPanic("crowdsec/acquis/waf/live")
|
defer trace.CatchPanic("crowdsec/acquis/waf/live")
|
||||||
w.logger.Infof("Starting WAF server on %s:%d%s", w.config.ListenAddr, w.config.ListenPort, w.config.Path)
|
w.logger.Infof("Starting WAF server on %s:%d%s", w.config.ListenAddr, w.config.ListenPort, w.config.Path)
|
||||||
t.Go(func() error {
|
t.Go(func() error {
|
||||||
err := w.server.ListenAndServe()
|
err := w.server.ListenAndServe()
|
||||||
|
@ -200,6 +204,7 @@ func (w *WafSource) Dump() interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
func processReqWithEngine(waf coraza.WAF, r *http.Request, uuid string) (*corazatypes.Interruption, corazatypes.Transaction, error) {
|
func processReqWithEngine(waf coraza.WAF, r *http.Request, uuid string) (*corazatypes.Interruption, corazatypes.Transaction, error) {
|
||||||
|
var in *corazatypes.Interruption
|
||||||
tx := waf.NewTransactionWithID(uuid)
|
tx := waf.NewTransactionWithID(uuid)
|
||||||
|
|
||||||
if tx.IsRuleEngineOff() {
|
if tx.IsRuleEngineOff() {
|
||||||
|
@ -240,7 +245,8 @@ func processReqWithEngine(waf coraza.WAF, r *http.Request, uuid string) (*coraza
|
||||||
tx.AddRequestHeader("Transfer-Encoding", r.TransferEncoding[0])
|
tx.AddRequestHeader("Transfer-Encoding", r.TransferEncoding[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
in := tx.ProcessRequestHeaders()
|
in = tx.ProcessRequestHeaders()
|
||||||
|
//if we're inband, we should stop here, but for outofband go to the end
|
||||||
if in != nil {
|
if in != nil {
|
||||||
log.Printf("headerss")
|
log.Printf("headerss")
|
||||||
return in, tx, nil
|
return in, tx, nil
|
||||||
|
@ -270,19 +276,22 @@ func processReqWithEngine(waf coraza.WAF, r *http.Request, uuid string) (*coraza
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Printf("done")
|
log.Printf("done -> %d", len(tx.MatchedRules()))
|
||||||
|
// if in != nil {
|
||||||
return nil, nil, nil
|
// log.Printf("exception while processing req")
|
||||||
|
// return in, tx, nil
|
||||||
|
// }
|
||||||
|
return nil, tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WafSource) TxToEvents(tx corazatypes.Transaction, r *http.Request) ([]types.Event, error) {
|
func (w *WafSource) TxToEvents(tx corazatypes.Transaction, r *http.Request, kind string) ([]types.Event, error) {
|
||||||
evts := []types.Event{}
|
evts := []types.Event{}
|
||||||
if tx == nil {
|
if tx == nil {
|
||||||
return nil, fmt.Errorf("tx is nil")
|
return nil, fmt.Errorf("tx is nil")
|
||||||
}
|
}
|
||||||
for idx, rule := range tx.MatchedRules() {
|
for idx, rule := range tx.MatchedRules() {
|
||||||
log.Printf("rule %d", idx)
|
log.Printf("rule %d", idx)
|
||||||
evt, err := w.RuleMatchToEvent(rule, tx, r)
|
evt, err := w.RuleMatchToEvent(rule, tx, r, kind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Cannot convert rule match to event")
|
return nil, errors.Wrap(err, "Cannot convert rule match to event")
|
||||||
}
|
}
|
||||||
|
@ -293,7 +302,7 @@ func (w *WafSource) TxToEvents(tx corazatypes.Transaction, r *http.Request) ([]t
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transforms a coraza interruption to a crowdsec event
|
// Transforms a coraza interruption to a crowdsec event
|
||||||
func (w *WafSource) RuleMatchToEvent(rule corazatypes.MatchedRule, tx corazatypes.Transaction, r *http.Request) (types.Event, error) {
|
func (w *WafSource) RuleMatchToEvent(rule corazatypes.MatchedRule, tx corazatypes.Transaction, r *http.Request, kind string) (types.Event, error) {
|
||||||
evt := types.Event{}
|
evt := types.Event{}
|
||||||
//we might want to change this based on in-band vs out-of-band ?
|
//we might want to change this based on in-band vs out-of-band ?
|
||||||
evt.Type = types.LOG
|
evt.Type = types.LOG
|
||||||
|
@ -306,8 +315,9 @@ func (w *WafSource) RuleMatchToEvent(rule corazatypes.MatchedRule, tx corazatype
|
||||||
//why ? because it's more consistent with the other data-sources etc. and it provides users with flexibility to alter our parsers
|
//why ? because it's more consistent with the other data-sources etc. and it provides users with flexibility to alter our parsers
|
||||||
CorazaEvent := map[string]interface{}{
|
CorazaEvent := map[string]interface{}{
|
||||||
//core rule info
|
//core rule info
|
||||||
|
"rule_type": kind,
|
||||||
"rule_id": rule.Rule().ID(),
|
"rule_id": rule.Rule().ID(),
|
||||||
"rule_action": tx.Interruption().Action,
|
//"rule_action": tx.Interruption().Action,
|
||||||
"rule_disruptive": rule.Disruptive(),
|
"rule_disruptive": rule.Disruptive(),
|
||||||
"rule_tags": rule.Rule().Tags(),
|
"rule_tags": rule.Rule().Tags(),
|
||||||
"rule_file": rule.Rule().File(),
|
"rule_file": rule.Rule().File(),
|
||||||
|
@ -323,6 +333,9 @@ func (w *WafSource) RuleMatchToEvent(rule corazatypes.MatchedRule, tx corazatype
|
||||||
"uri": rule.URI(),
|
"uri": rule.URI(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tx.Interruption() != nil {
|
||||||
|
CorazaEvent["rule_action"] = tx.Interruption().Action
|
||||||
|
}
|
||||||
corazaEventB, err := json.Marshal(CorazaEvent)
|
corazaEventB, err := json.Marshal(CorazaEvent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return evt, fmt.Errorf("Unable to marshal coraza alert: %w", err)
|
return evt, fmt.Errorf("Unable to marshal coraza alert: %w", err)
|
||||||
|
@ -352,7 +365,7 @@ func (w *WafSource) wafHandler(rw http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if in != nil {
|
if in != nil {
|
||||||
events, err := w.TxToEvents(tx, r)
|
events, err := w.TxToEvents(tx, r, "inband")
|
||||||
log.Infof("Request blocked by WAF, %d events to send", len(events))
|
log.Infof("Request blocked by WAF, %d events to send", len(events))
|
||||||
for _, evt := range events {
|
for _, evt := range events {
|
||||||
w.outChan <- evt
|
w.outChan <- evt
|
||||||
|
@ -373,8 +386,9 @@ func (w *WafSource) wafHandler(rw http.ResponseWriter, r *http.Request) {
|
||||||
log.Errorf("Error while processing request : %s", err)
|
log.Errorf("Error while processing request : %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if in2 != nil {
|
if tx2 != nil && len(tx2.MatchedRules()) > 0 {
|
||||||
events, err := w.TxToEvents(tx2, r)
|
log.Printf("got events and stuff to do")
|
||||||
|
events, err := w.TxToEvents(tx2, r, "outofband")
|
||||||
log.Infof("Request triggered by WAF, %d events to send", len(events))
|
log.Infof("Request triggered by WAF, %d events to send", len(events))
|
||||||
for _, evt := range events {
|
for _, evt := range events {
|
||||||
w.outChan <- evt
|
w.outChan <- evt
|
||||||
|
|
|
@ -274,6 +274,10 @@ func (n *Node) process(p *types.Event, ctx UnixParserCtx, expressionEnv map[stri
|
||||||
switch out := output.(type) {
|
switch out := output.(type) {
|
||||||
case string:
|
case string:
|
||||||
gstr = out
|
gstr = out
|
||||||
|
case int:
|
||||||
|
gstr = fmt.Sprintf("%d", out)
|
||||||
|
case float64, float32:
|
||||||
|
gstr = fmt.Sprintf("%f", out)
|
||||||
default:
|
default:
|
||||||
clog.Errorf("unexpected return type for RunTimeValue : %T", output)
|
clog.Errorf("unexpected return type for RunTimeValue : %T", output)
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,8 @@ func (n *Node) ProcessStatics(statics []types.ExtraField, event *types.Event) er
|
||||||
value = out
|
value = out
|
||||||
case int:
|
case int:
|
||||||
value = strconv.Itoa(out)
|
value = strconv.Itoa(out)
|
||||||
|
case float64, float32:
|
||||||
|
value = fmt.Sprintf("%f", out)
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
clog.Warnf("Expression '%s' returned a map, please use ToJsonString() to convert it to string if you want to keep it as is, or refine your expression to extract a string", static.ExpValue)
|
clog.Warnf("Expression '%s' returned a map, please use ToJsonString() to convert it to string if you want to keep it as is, or refine your expression to extract a string", static.ExpValue)
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
|
@ -139,7 +141,7 @@ func (n *Node) ProcessStatics(statics []types.ExtraField, event *types.Event) er
|
||||||
case nil:
|
case nil:
|
||||||
clog.Debugf("Expression '%s' returned nil, skipping", static.ExpValue)
|
clog.Debugf("Expression '%s' returned nil, skipping", static.ExpValue)
|
||||||
default:
|
default:
|
||||||
clog.Errorf("unexpected return type for RunTimeValue : %T", output)
|
clog.Errorf("unexpected return type for '%s' : %T", static.ExpValue, output)
|
||||||
return errors.New("unexpected return type for RunTimeValue")
|
return errors.New("unexpected return type for RunTimeValue")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue