add post_eval hook

This commit is contained in:
Sebastien Blot 2023-12-04 10:29:14 +01:00
parent d9355e8c3a
commit 60faeaa7d7
No known key found for this signature in database
GPG key ID: DFC2902F40449F6A
3 changed files with 62 additions and 5 deletions

View file

@ -106,7 +106,7 @@ func (r *WaapRunner) processRequest(tx waf.ExtendedTransaction, request *waf.Par
} }
} }
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 ? request.Tx.ProcessURI(request.URI, request.Method, request.Proto)
for k, vr := range request.Headers { for k, vr := range request.Headers {
for _, v := range vr { for _, v := range vr {
@ -150,7 +150,11 @@ func (r *WaapRunner) processRequest(tx waf.ExtendedTransaction, request *waf.Par
if in != nil { if in != nil {
r.logger.Debugf("rules matched for body : %d", in.RuleID) r.logger.Debugf("rules matched for body : %d", in.RuleID)
return nil }
err = r.WaapRuntime.ProcessPostEvalRules(request)
if err != nil {
r.logger.Errorf("unable to process PostEval rules: %s", err)
} }
return nil return nil

View file

@ -26,6 +26,7 @@ type Hook struct {
const ( const (
hookOnLoad = iota hookOnLoad = iota
hookPreEval hookPreEval
hookPostEval
hookOnMatch hookOnMatch
) )
@ -38,6 +39,8 @@ func (h *Hook) Build(hookStage int) error {
ctx = GetOnLoadEnv(&WaapRuntimeConfig{}) ctx = GetOnLoadEnv(&WaapRuntimeConfig{})
case hookPreEval: case hookPreEval:
ctx = GetPreEvalEnv(&WaapRuntimeConfig{}, &ParsedRequest{}) ctx = GetPreEvalEnv(&WaapRuntimeConfig{}, &ParsedRequest{})
case hookPostEval:
ctx = GetPostEvalEnv(&WaapRuntimeConfig{}, &ParsedRequest{})
case hookOnMatch: case hookOnMatch:
ctx = GetOnMatchEnv(&WaapRuntimeConfig{}, &ParsedRequest{}, types.Event{}) ctx = GetOnMatchEnv(&WaapRuntimeConfig{}, &ParsedRequest{}, types.Event{})
} }
@ -83,6 +86,7 @@ type WaapRuntimeConfig struct {
DefaultRemediation string DefaultRemediation string
CompiledOnLoad []Hook CompiledOnLoad []Hook
CompiledPreEval []Hook CompiledPreEval []Hook
CompiledPostEval []Hook
CompiledOnMatch []Hook CompiledOnMatch []Hook
CompiledVariablesTracking []*regexp.Regexp CompiledVariablesTracking []*regexp.Regexp
Config *WaapConfig Config *WaapConfig
@ -107,6 +111,7 @@ type WaapConfig struct {
PassedHTTPCode int `yaml:"passed_http_code"` PassedHTTPCode int `yaml:"passed_http_code"`
OnLoad []Hook `yaml:"on_load"` OnLoad []Hook `yaml:"on_load"`
PreEval []Hook `yaml:"pre_eval"` PreEval []Hook `yaml:"pre_eval"`
PostEval []Hook `yaml:"post_eval"`
OnMatch []Hook `yaml:"on_match"` OnMatch []Hook `yaml:"on_match"`
VariablesTracking []string `yaml:"variables_tracking"` VariablesTracking []string `yaml:"variables_tracking"`
InbandOptions WaapSubEngineOpts `yaml:"inband_options"` InbandOptions WaapSubEngineOpts `yaml:"inband_options"`
@ -239,6 +244,14 @@ func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
ret.CompiledPreEval = append(ret.CompiledPreEval, hook) ret.CompiledPreEval = append(ret.CompiledPreEval, hook)
} }
for _, hook := range wc.PostEval {
err := hook.Build(hookPostEval)
if err != nil {
return nil, fmt.Errorf("unable to build post_eval hook : %s", err)
}
ret.CompiledPostEval = append(ret.CompiledPostEval, hook)
}
for _, hook := range wc.OnMatch { for _, hook := range wc.OnMatch {
err := hook.Build(hookOnMatch) err := hook.Build(hookOnMatch)
if err != nil { if err != nil {
@ -268,7 +281,7 @@ func (w *WaapRuntimeConfig) ProcessOnLoadRules() error {
switch t := output.(type) { switch t := output.(type) {
case bool: case bool:
if !t { if !t {
log.Infof("filter didnt match") log.Debugf("filter didnt match")
continue continue
} }
default: default:
@ -298,7 +311,7 @@ func (w *WaapRuntimeConfig) ProcessOnMatchRules(request *ParsedRequest, evt type
switch t := output.(type) { switch t := output.(type) {
case bool: case bool:
if !t { if !t {
log.Infof("filter didnt match") log.Debugf("filter didnt match")
continue continue
} }
default: default:
@ -327,7 +340,7 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request *ParsedRequest) error {
switch t := output.(type) { switch t := output.(type) {
case bool: case bool:
if !t { if !t {
log.Infof("filter didnt match") log.Debugf("filter didnt match")
continue continue
} }
default: default:
@ -348,6 +361,37 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request *ParsedRequest) error {
return nil return nil
} }
func (w *WaapRuntimeConfig) ProcessPostEvalRules(request *ParsedRequest) error {
for _, rule := range w.CompiledPostEval {
if rule.FilterExpr != nil {
output, err := exprhelpers.Run(rule.FilterExpr, GetPostEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil {
return fmt.Errorf("unable to run waap post_eval filter %s : %w", rule.Filter, err)
}
switch t := output.(type) {
case bool:
if !t {
log.Debugf("filter didnt match")
continue
}
default:
log.Errorf("Filter must return a boolean, can't filter")
continue
}
}
// here means there is no filter or the filter matched
for _, applyExpr := range rule.ApplyExpr {
_, err := exprhelpers.Run(applyExpr, GetPostEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil {
log.Errorf("unable to apply waap post_eval expr: %s", err)
continue
}
}
}
return nil
}
/* @sbl / @tko /* @sbl / @tko
add the helpers to: add the helpers to:
- remove by id-range - remove by id-range

View file

@ -54,6 +54,15 @@ func GetPreEvalEnv(w *WaapRuntimeConfig, request *ParsedRequest) map[string]inte
} }
} }
func GetPostEvalEnv(w *WaapRuntimeConfig, request *ParsedRequest) map[string]interface{} {
//FIXME: use expr.Function instead of this
return map[string]interface{}{
"IsInBand": request.IsInBand,
"IsOutBand": request.IsOutBand,
"DumpRequest": request.DumpRequest,
}
}
func GetOnMatchEnv(w *WaapRuntimeConfig, request *ParsedRequest, evt types.Event) map[string]interface{} { func GetOnMatchEnv(w *WaapRuntimeConfig, request *ParsedRequest, evt types.Event) map[string]interface{} {
//FIXME: use expr.Function instead of this //FIXME: use expr.Function instead of this
return map[string]interface{}{ return map[string]interface{}{