up
This commit is contained in:
parent
d3ce4cbf8e
commit
535738b962
4 changed files with 146 additions and 34 deletions
|
@ -180,6 +180,10 @@ func (w *WaapSource) Configure(yamlConfig []byte, logger *log.Entry) error {
|
|||
logger: wafLogger,
|
||||
WaapRuntime: &wrt,
|
||||
}
|
||||
err := runner.Init()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initialize runner : %s", err)
|
||||
}
|
||||
w.WaapRunners[nbRoutine] = runner
|
||||
//most likely missign somethign here to actually start the runner :)
|
||||
}
|
||||
|
@ -269,10 +273,14 @@ func (w *WaapSource) waapHandler(rw http.ResponseWriter, r *http.Request) {
|
|||
w.InChan <- parsedRequest
|
||||
|
||||
response := <-parsedRequest.ResponseChannel
|
||||
log.Infof("resp %+v", response)
|
||||
|
||||
rw.WriteHeader(response.HTTPResponseCode)
|
||||
body, err := json.Marshal(BodyResponse{Action: response.Action})
|
||||
waapResponse := w.WaapRuntime.GenerateResponse(response.InBandInterrupt)
|
||||
|
||||
log.Infof("resp %+v", response)
|
||||
log.Infof("waap resp %+v", waapResponse)
|
||||
|
||||
rw.WriteHeader(waapResponse.HTTPStatus)
|
||||
body, err := json.Marshal(BodyResponse{Action: waapResponse.Action})
|
||||
if err != nil {
|
||||
log.Errorf("unable to marshal response: %s", err)
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
package wafacquisition
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/crowdsecurity/coraza/v3"
|
||||
"github.com/crowdsecurity/coraza/v3/experimental"
|
||||
corazatypes "github.com/crowdsecurity/coraza/v3/types"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/types"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/waf"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
@ -22,6 +27,114 @@ type WaapRunner struct {
|
|||
logger *log.Entry
|
||||
}
|
||||
|
||||
func (r *WaapRunner) Init() error {
|
||||
var err error
|
||||
fs := os.DirFS(csconfig.DataDir)
|
||||
|
||||
inBandRules := ""
|
||||
outOfBandRules := ""
|
||||
|
||||
for _, collection := range r.WaapRuntime.InBandRules {
|
||||
inBandRules += collection.String()
|
||||
}
|
||||
|
||||
for _, collection := range r.WaapRuntime.OutOfBandRules {
|
||||
outOfBandRules += collection.String()
|
||||
}
|
||||
|
||||
r.WaapInbandEngine, err = coraza.NewWAF(
|
||||
coraza.NewWAFConfig().WithDirectives(inBandRules).WithRootFS(fs),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initialize inband engine : %w", err)
|
||||
}
|
||||
|
||||
r.WaapOutbandEngine, err = coraza.NewWAF(
|
||||
coraza.NewWAFConfig().WithDirectives(outOfBandRules).WithRootFS(fs),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initialize outband engine : %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *WaapRunner) ProcessInBandRules(request *waf.ParsedRequest) error {
|
||||
var in *corazatypes.Interruption
|
||||
var err error
|
||||
|
||||
tx := r.WaapInbandEngine.NewTransactionWithID(request.UUID)
|
||||
|
||||
request.Tx = tx.(experimental.FullTransaction)
|
||||
|
||||
if request.Tx.IsRuleEngineOff() {
|
||||
r.logger.Debugf("rule engine is off, skipping")
|
||||
return nil
|
||||
}
|
||||
|
||||
defer func() {
|
||||
request.Tx.ProcessLogging()
|
||||
//We don't close the transaction here, as it will reset coraza internal state and break out of bands rules
|
||||
}()
|
||||
|
||||
request.Tx.ProcessConnection(request.RemoteAddr, 0, "", 0)
|
||||
request.Tx.ProcessURI(request.URI, request.Method, request.Proto) //TODO: The doc mentions that GET args needs to be added, but we never call AddArguments ?
|
||||
|
||||
for k, vr := range request.Headers {
|
||||
for _, v := range vr {
|
||||
request.Tx.AddRequestHeader(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
if request.ClientHost != "" {
|
||||
request.Tx.AddRequestHeader("Host", request.ClientHost)
|
||||
request.Tx.SetServerName(request.ClientHost)
|
||||
}
|
||||
|
||||
if request.TransferEncoding != nil {
|
||||
request.Tx.AddRequestHeader("Transfer-Encoding", request.TransferEncoding[0])
|
||||
}
|
||||
|
||||
in = request.Tx.ProcessRequestHeaders()
|
||||
|
||||
if in != nil {
|
||||
r.logger.Infof("inband rules matched for headers : %d", in.Action)
|
||||
return nil
|
||||
}
|
||||
|
||||
if request.Body != nil && len(request.Body) > 0 {
|
||||
in, _, err = request.Tx.WriteRequestBody(request.Body)
|
||||
if err != nil {
|
||||
r.logger.Errorf("unable to write request body : %s", err)
|
||||
return err
|
||||
}
|
||||
if in != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
in, err = request.Tx.ProcessRequestBody()
|
||||
|
||||
if err != nil {
|
||||
r.logger.Errorf("unable to process request body : %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if in != nil {
|
||||
r.logger.Infof("inband rules matched for body : %d", in.RuleID)
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *WaapRunner) ProcessOutOfBandRules(request waf.ParsedRequest) (*corazatypes.Interruption, error) {
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *WaapRunner) Run(t *tomb.Tomb) error {
|
||||
r.logger.Infof("Waap Runner ready to process event")
|
||||
for {
|
||||
|
@ -45,11 +158,16 @@ func (r *WaapRunner) Run(t *tomb.Tomb) error {
|
|||
}
|
||||
log.Infof("now response is -> %s", r.WaapRuntime.Response.Action)
|
||||
//inband WAAP rules
|
||||
err = r.WaapRuntime.ProcessInBandRules(request)
|
||||
err = r.ProcessInBandRules(&request)
|
||||
if err != nil {
|
||||
r.logger.Errorf("unable to process InBand rules: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if in := request.Tx.Interruption(); in != nil {
|
||||
r.logger.Debugf("inband rules matched : %d", in.RuleID)
|
||||
r.WaapRuntime.Response.InBandInterrupt = true
|
||||
}
|
||||
elapsed := time.Since(startParsing)
|
||||
WafInbandParsingHistogram.With(prometheus.Labels{"source": request.RemoteAddr}).Observe(elapsed.Seconds())
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
|
||||
"github.com/antonmedv/expr"
|
||||
"github.com/antonmedv/expr/vm"
|
||||
corazatypes "github.com/crowdsecurity/coraza/v3/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
@ -131,7 +130,7 @@ func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
|
|||
|
||||
//load rules
|
||||
for _, rule := range wc.OutOfBandRules {
|
||||
wc.Logger.Debugf("loading outofband rule %s", rule)
|
||||
wc.Logger.Infof("loading outofband rule %s", rule)
|
||||
collection, err := LoadCollection(rule)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load outofband rule %s : %s", rule, err)
|
||||
|
@ -139,8 +138,9 @@ func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
|
|||
ret.OutOfBandRules = append(ret.OutOfBandRules, collection)
|
||||
}
|
||||
|
||||
wc.Logger.Infof("Loaded %d outofband rules", len(ret.OutOfBandRules))
|
||||
for _, rule := range wc.InBandRules {
|
||||
wc.Logger.Debugf("loading inband rule %s", rule)
|
||||
wc.Logger.Infof("loading inband rule %s", rule)
|
||||
collection, err := LoadCollection(rule)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load inband rule %s : %s", rule, err)
|
||||
|
@ -148,6 +148,8 @@ func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
|
|||
ret.InBandRules = append(ret.InBandRules, collection)
|
||||
}
|
||||
|
||||
wc.Logger.Infof("Loaded %d inband rules", len(ret.InBandRules))
|
||||
|
||||
//load hooks
|
||||
for _, hook := range wc.OnLoad {
|
||||
err := hook.Build()
|
||||
|
@ -311,45 +313,21 @@ func (w *WaapRuntimeConfig) SetHTTPCode(code int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) ProcessInBandRules(request ParsedRequest) error {
|
||||
for _, rule := range w.InBandRules {
|
||||
_, err := rule.Eval(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to process inband rule %s : %s", rule.GetDisplayName(), err)
|
||||
}
|
||||
//...
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) ProcessOutOfBandRules(request ParsedRequest) (*corazatypes.Interruption, error) {
|
||||
for _, rule := range w.OutOfBandRules {
|
||||
interrupt, err := rule.Eval(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to process inband rule %s : %s", rule.GetDisplayName(), err)
|
||||
}
|
||||
if interrupt != nil {
|
||||
return interrupt, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type BodyResponse struct {
|
||||
Action string `json:"action"`
|
||||
HTTPStatus int `json:"http_status"`
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) GenerateResponse(interrupted bool) (BodyResponse, error) {
|
||||
func (w *WaapRuntimeConfig) GenerateResponse(interrupted bool) BodyResponse {
|
||||
resp := BodyResponse{}
|
||||
//if there is no interrupt, we should allow with default code
|
||||
if !interrupted {
|
||||
resp.Action = w.Config.DefaultPassAction
|
||||
resp.HTTPStatus = w.Config.PassedHTTPCode
|
||||
return resp, nil
|
||||
return resp
|
||||
}
|
||||
resp.Action = w.Config.DefaultRemediation
|
||||
resp.HTTPStatus = w.Config.BlockedHTTPCode
|
||||
|
||||
return resp, nil
|
||||
return resp
|
||||
}
|
||||
|
|
|
@ -120,3 +120,11 @@ func (w WaapCollection) Eval(req ParsedRequest) (*corazatypes.Interruption, erro
|
|||
func (w WaapCollection) GetDisplayName() string {
|
||||
return w.collectionName
|
||||
}
|
||||
|
||||
func (w WaapCollection) String() string {
|
||||
ret := ""
|
||||
for _, rule := range w.Rules {
|
||||
ret += rule + "\n"
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue