2023-06-16 10:19:08 +00:00
|
|
|
package wafacquisition
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
2023-07-13 14:22:21 +00:00
|
|
|
"github.com/crowdsecurity/coraza/v3/experimental"
|
|
|
|
"github.com/crowdsecurity/crowdsec/pkg/types"
|
2023-07-04 15:36:56 +00:00
|
|
|
"github.com/crowdsecurity/crowdsec/pkg/waf"
|
2023-07-13 14:20:04 +00:00
|
|
|
"github.com/davecgh/go-spew/spew"
|
2023-07-10 16:00:19 +00:00
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
2023-07-04 15:36:56 +00:00
|
|
|
log "github.com/sirupsen/logrus"
|
2023-06-16 10:19:08 +00:00
|
|
|
)
|
|
|
|
|
2023-07-13 14:20:04 +00:00
|
|
|
func EventFromRequest(r waf.ParsedRequest) (types.Event, error) {
|
2023-06-16 10:19:08 +00:00
|
|
|
evt := types.Event{}
|
|
|
|
//we might want to change this based on in-band vs out-of-band ?
|
|
|
|
evt.Type = types.LOG
|
|
|
|
evt.ExpectMode = types.LIVE
|
|
|
|
//def needs fixing
|
|
|
|
evt.Stage = "s00-raw"
|
|
|
|
evt.Process = true
|
2023-07-13 14:20:04 +00:00
|
|
|
evt.Parsed = map[string]string{
|
|
|
|
"source_ip": r.ClientIP,
|
|
|
|
"target_host": r.Host,
|
|
|
|
"target_uri": r.URI,
|
|
|
|
"method": r.Method,
|
|
|
|
"req_uuid": r.Tx.ID(),
|
2023-07-18 16:12:17 +00:00
|
|
|
"source": "coraza",
|
|
|
|
|
|
|
|
//TBD:
|
|
|
|
//http_status
|
|
|
|
//user_agent
|
|
|
|
|
2023-06-16 10:19:08 +00:00
|
|
|
}
|
|
|
|
evt.Line = types.Line{
|
|
|
|
Time: time.Now(),
|
|
|
|
//should we add some info like listen addr/port/path ?
|
2023-07-18 16:12:17 +00:00
|
|
|
Labels: map[string]string{"type": "coraza-waf"},
|
2023-06-16 10:19:08 +00:00
|
|
|
Process: true,
|
|
|
|
Module: "waf",
|
|
|
|
Src: "waf",
|
2023-07-13 14:20:04 +00:00
|
|
|
Raw: "dummy-waf-data", //we discard empty Line.Raw items :)
|
2023-06-16 10:19:08 +00:00
|
|
|
}
|
2023-07-13 14:20:04 +00:00
|
|
|
evt.Waap = []map[string]interface{}{}
|
2023-06-16 10:19:08 +00:00
|
|
|
|
|
|
|
return evt, nil
|
|
|
|
}
|
2023-07-13 14:20:04 +00:00
|
|
|
|
|
|
|
func LogWaapEvent(evt *types.Event) {
|
|
|
|
log.WithFields(log.Fields{
|
|
|
|
"module": "waf",
|
|
|
|
"source": evt.Parsed["source_ip"],
|
|
|
|
"target_uri": evt.Parsed["target_uri"],
|
|
|
|
}).Infof("%s triggered %d rules [%+v]", evt.Parsed["source_ip"], len(evt.Waap), evt.Waap.GetRuleIDs())
|
|
|
|
log.Infof("%s", evt.Waap)
|
|
|
|
}
|
|
|
|
|
|
|
|
func AccumulateTxToEvent(tx experimental.FullTransaction, kind string, evt *types.Event) error {
|
|
|
|
|
|
|
|
if tx.IsInterrupted() {
|
|
|
|
log.Infof("interrupted() = %t", tx.IsInterrupted())
|
|
|
|
log.Infof("interrupted.action = %s", tx.Interruption().Action)
|
|
|
|
if evt.Meta == nil {
|
|
|
|
evt.Meta = map[string]string{}
|
|
|
|
}
|
2023-07-18 16:12:17 +00:00
|
|
|
evt.Parsed["interrupted"] = "true"
|
|
|
|
evt.Parsed["action"] = tx.Interruption().Action
|
|
|
|
|
2023-07-13 14:20:04 +00:00
|
|
|
evt.Meta["waap_interrupted"] = "1"
|
|
|
|
evt.Meta["waap_action"] = tx.Interruption().Action
|
|
|
|
}
|
|
|
|
log.Infof("TX %s", spew.Sdump(tx.MatchedRules()))
|
|
|
|
for _, rule := range tx.MatchedRules() {
|
|
|
|
if rule.Message() == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
WafRuleHits.With(prometheus.Labels{"rule_id": fmt.Sprintf("%d", rule.Rule().ID()), "type": kind}).Inc()
|
|
|
|
|
|
|
|
corazaRule := map[string]interface{}{
|
|
|
|
"id": rule.Rule().ID(),
|
|
|
|
"uri": evt.Parsed["uri"],
|
|
|
|
"rule_type": kind,
|
|
|
|
"method": evt.Parsed["method"],
|
|
|
|
"disruptive": rule.Disruptive(),
|
|
|
|
"tags": rule.Rule().Tags(),
|
|
|
|
"file": rule.Rule().File(),
|
|
|
|
"file_line": rule.Rule().Line(),
|
|
|
|
"revision": rule.Rule().Revision(),
|
|
|
|
"secmark": rule.Rule().SecMark(),
|
|
|
|
"accuracy": rule.Rule().Accuracy(),
|
|
|
|
"msg": rule.Message(),
|
|
|
|
"severity": rule.Rule().Severity().String(),
|
|
|
|
}
|
|
|
|
evt.Waap = append(evt.Waap, corazaRule)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|