bui 1 year ago
parent
commit
2e60e8021c

+ 12 - 7
pkg/acquisition/modules/waap/waap.go

@@ -52,6 +52,11 @@ type WaapSource struct {
 	WaapRunners []WaapRunner //one for each go-routine
 }
 
+// @tko + @sbl : we might want to get rid of that or improve it
+type BodyResponse struct {
+	Action string `json:"action"`
+}
+
 func (wc *WaapSource) UnmarshalConfig(yamlConfig []byte) error {
 
 	err := yaml.UnmarshalStrict(yamlConfig, &wc.config)
@@ -165,10 +170,13 @@ func (w *WaapSource) Configure(yamlConfig []byte, logger *log.Entry) error {
 			})
 		}
 
+		//we copy WaapRutime for each runner
+		wrt := *w.WaapRuntime
 		runner := WaapRunner{
-			inChan: w.InChan,
-			UUID:   wafUUID,
-			logger: wafLogger,
+			inChan:      w.InChan,
+			UUID:        wafUUID,
+			logger:      wafLogger,
+			WaapRuntime: &wrt,
 		}
 		w.WaapRunners[nbRoutine] = runner
 		//most likely missign somethign here to actually start the runner :)
@@ -247,10 +255,6 @@ func (w *WaapSource) Dump() interface{} {
 	return w
 }
 
-type BodyResponse struct {
-	Action string `json:"action"`
-}
-
 // should this be in the runner ?
 func (w *WaapSource) waapHandler(rw http.ResponseWriter, r *http.Request) {
 	// parse the request only once
@@ -264,6 +268,7 @@ func (w *WaapSource) waapHandler(rw http.ResponseWriter, r *http.Request) {
 
 	message := <-parsedRequest.ResponseChannel
 
+	//@tko this parts needs to be redone
 	if message.Err != nil {
 		log.Errorf("Error while processing InBAND: %s", err)
 		rw.WriteHeader(http.StatusInternalServerError)

+ 2 - 3
pkg/acquisition/modules/waap/waap_runner.go

@@ -31,10 +31,10 @@ func (r *WaapRunner) Run(t *tomb.Tomb) error {
 			return nil
 		case request := <-r.inChan:
 			r.logger.Infof("Requests handled by runner %s", request.UUID)
+			r.WaapRuntime.ClearResponse()
 
-			//tx := waf.NewExtendedTransaction(r.WaapInbandEngine, r.UUID)
 			WafReqCounter.With(prometheus.Labels{"source": request.RemoteAddr}).Inc()
-			//measure the time spent in the WAF
+			//to measure the time spent in the WAF
 			startParsing := time.Now()
 
 			//pre eval (expr) rules
@@ -43,7 +43,6 @@ func (r *WaapRunner) Run(t *tomb.Tomb) error {
 				r.logger.Errorf("unable to process PreEval rules: %s", err)
 				continue
 			}
-
 			//inband WAAP rules
 			interrupt, err := r.WaapRuntime.ProcessInBandRules(request)
 			elapsed := time.Since(startParsing)

+ 11 - 12
pkg/waf/env.go

@@ -25,18 +25,17 @@ func (t *ExtendedTransaction) RemoveRuleByIDWithError(id int) error {
 	return nil
 }
 
-func GetEnv() map[string]interface{} {
-	ResponseRequest := ResponseRequest{}
-	ParsedRequest := ParsedRequest{}
-	Rules := &WaapCollection{}
-	Tx := ExtendedTransaction{}
-
+// simply used to ease the compilation & runtime of the hooks
+func GetHookEnv(w WaapRuntimeConfig, request ParsedRequest) map[string]interface{} {
 	return map[string]interface{}{
-		"rules":              Rules,
-		"req":                ParsedRequest,
-		"SetRemediation":     ResponseRequest.SetRemediation,
-		"SetRemediationByID": ResponseRequest.SetRemediationByID,
-		"CancelEvent":        ResponseRequest.CancelEvent,
-		"RemoveRuleByID":     Tx.RemoveRuleByIDWithError,
+		"inband_rules":          w.InBandRules,
+		"outband_rules":         w.OutOfBandRules,
+		"req":                   request,
+		"RemoveInbandRuleByID":  w.RemoveInbandRuleByID,
+		"RemoveOutbandRuleByID": w.RemoveOutbandRuleByID,
+		"SetAction":             w.SetAction,
+		"SetHTTPCode":           w.SetHTTPCode,
+		"SetActionByID":         w.SetActionnByID,
+		"CancelEvent":           w.CancelEvent,
 	}
 }

+ 22 - 21
pkg/waf/request.go

@@ -36,29 +36,29 @@ func NewResponseRequest(Tx experimental.FullTransaction, in *corazatypes.Interru
 	}
 }
 
-func (r *ResponseRequest) SetRemediation(remediation string) error {
-	if r.Interruption == nil {
-		return nil
-	}
-	r.Interruption.Action = remediation
-	return nil
-}
+// func (r *ResponseRequest) SetRemediation(remediation string) error {
+// 	if r.Interruption == nil {
+// 		return nil
+// 	}
+// 	r.Interruption.Action = remediation
+// 	return nil
+// }
 
-func (r *ResponseRequest) SetRemediationByID(ID int, remediation string) error {
-	if r.Interruption == nil {
-		return nil
-	}
-	if r.Interruption.RuleID == ID {
-		r.Interruption.Action = remediation
-	}
-	return nil
-}
+// func (r *ResponseRequest) SetRemediationByID(ID int, remediation string) error {
+// 	if r.Interruption == nil {
+// 		return nil
+// 	}
+// 	if r.Interruption.RuleID == ID {
+// 		r.Interruption.Action = remediation
+// 	}
+// 	return nil
+// }
 
-func (r *ResponseRequest) CancelEvent() error {
-	// true by default
-	r.SendEvents = false
-	return nil
-}
+// func (r *ResponseRequest) CancelEvent() error {
+// 	// true by default
+// 	r.SendEvents = false
+// 	return nil
+// }
 
 type ParsedRequest struct {
 	RemoteAddr       string
@@ -77,6 +77,7 @@ type ParsedRequest struct {
 	ResponseChannel  chan ResponseRequest
 }
 
+// Generate a ParsedRequest from a http.Request. ParsedRequest can be consumed by the Waap Engine
 func NewParsedRequestFromRequest(r *http.Request) (ParsedRequest, error) {
 	var err error
 	body := make([]byte, 0)

+ 97 - 25
pkg/waf/waap.go

@@ -21,6 +21,7 @@ type Hook struct {
 	ApplyExpr []*vm.Program `yaml:"-"`
 }
 
+// @tko : todo - debug mode
 func (h *Hook) Build() error {
 
 	if h.Filter != "" {
@@ -31,7 +32,7 @@ func (h *Hook) Build() error {
 		h.FilterExpr = program
 	}
 	for _, apply := range h.Apply {
-		program, err := expr.Compile(apply, GetExprWAFOptions(GetEnv())...)
+		program, err := expr.Compile(apply, GetExprWAFOptions(GetHookEnv(WaapRuntimeConfig{}, ParsedRequest{}))...)
 		if err != nil {
 			return fmt.Errorf("unable to compile apply %s : %w", apply, err)
 		}
@@ -40,18 +41,30 @@ func (h *Hook) Build() error {
 	return nil
 }
 
+type WaapTempResponse struct {
+	InBandInterrupt    bool
+	OutOfBandInterrupt bool
+	Action             string //allow, deny, captcha, log
+	HTTPResponseCode   int
+	SendEvent          bool //do we send an internal event on rule match
+}
+
 // runtime version of WaapConfig
 type WaapRuntimeConfig struct {
 	Name                      string
 	OutOfBandRules            []WaapCollection
-	OutOfBandTx               ExtendedTransaction //is it a good idea ?
 	InBandRules               []WaapCollection
-	InBandTx                  ExtendedTransaction //is it a good idea ?
 	DefaultRemediation        string
 	CompiledOnLoad            []Hook
 	CompiledPreEval           []Hook
 	CompiledOnMatch           []Hook
 	CompiledVariablesTracking []*regexp.Regexp
+	Config                    *WaapConfig
+
+	//those are ephemeral, created/destroyed with every req
+	OutOfBandTx ExtendedTransaction //is it a good idea ?
+	InBandTx    ExtendedTransaction //is it a good idea ?
+	Response    WaapTempResponse
 }
 
 type WaapConfig struct {
@@ -59,12 +72,24 @@ type WaapConfig struct {
 	OutOfBandRules     []string `yaml:"outofband_rules"`
 	InBandRules        []string `yaml:"inband_rules"`
 	DefaultRemediation string   `yaml:"default_remediation"`
+	DefaultPassAction  string   `yaml:"default_pass_action"`
+	BlockedHTTPCode    int      `yaml:"blocked_http_code"`
+	PassedHTTPCode     int      `yaml:"passed_http_code"`
 	OnLoad             []Hook   `yaml:"on_load"`
 	PreEval            []Hook   `yaml:"pre_eval"`
 	OnMatch            []Hook   `yaml:"on_match"`
 	VariablesTracking  []string `yaml:"variables_tracking"`
 }
 
+func (w *WaapRuntimeConfig) ClearResponse() {
+	log.Infof("#-> %p", w)
+	w.Response = WaapTempResponse{}
+	log.Infof("-> %p", w.Config)
+	w.Response.Action = w.Config.DefaultPassAction
+	w.Response.HTTPResponseCode = w.Config.PassedHTTPCode
+	w.Response.SendEvent = true
+}
+
 func (wc *WaapConfig) Load(file string) error {
 	yamlFile, err := os.ReadFile(file)
 	if err != nil {
@@ -74,6 +99,21 @@ func (wc *WaapConfig) Load(file string) error {
 	if err != nil {
 		return fmt.Errorf("unable to parse yaml file %s : %s", file, err)
 	}
+	if wc.Name == "" {
+		return fmt.Errorf("name cannot be empty")
+	}
+	if wc.DefaultRemediation == "" {
+		return fmt.Errorf("default_remediation cannot be empty")
+	}
+	if wc.BlockedHTTPCode == 0 {
+		wc.BlockedHTTPCode = 403
+	}
+	if wc.PassedHTTPCode == 0 {
+		wc.PassedHTTPCode = 200
+	}
+	if wc.DefaultPassAction == "" {
+		wc.DefaultPassAction = "allow"
+	}
 	return nil
 
 }
@@ -81,6 +121,7 @@ func (wc *WaapConfig) Load(file string) error {
 func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
 	ret := &WaapRuntimeConfig{}
 	ret.Name = wc.Name
+	ret.Config = wc
 	ret.DefaultRemediation = wc.DefaultRemediation
 
 	//load rules
@@ -160,13 +201,12 @@ func (w *WaapRuntimeConfig) ProcessOnMatchRules(request ParsedRequest, response
 		}
 		for _, applyExpr := range rule.ApplyExpr {
 			_, err := expr.Run(applyExpr, map[string]interface{}{
-				//"rules":                 w.InBandTx.Tx.Rules, //what is it supposed to be ? matched rules ?
-				"req":                   request,
-				"RemoveInbandRuleByID":  w.RemoveInbandRuleByID,
-				"RemoveOutbandRuleByID": w.RemoveOutbandRuleByID,
-				"SetRemediation":        response.SetRemediation,
-				"SetRemediationByID":    response.SetRemediationByID,
-				"CancelEvent":           response.CancelEvent,
+				// "req":                   request,
+				// "RemoveInbandRuleByID":  w.RemoveInbandRuleByID,
+				// "RemoveOutbandRuleByID": w.RemoveOutbandRuleByID,
+				// "SetAction":             response.SetAction,
+				// "SetRemediationByID":    response.SetRemediationByID,
+				// "CancelEvent":           response.CancelEvent,
 			})
 			if err != nil {
 				log.Errorf("unable to apply filter: %s", err)
@@ -180,10 +220,7 @@ func (w *WaapRuntimeConfig) ProcessOnMatchRules(request ParsedRequest, response
 func (w *WaapRuntimeConfig) ProcessPreEvalRules(request ParsedRequest) error {
 	for _, rule := range w.CompiledPreEval {
 		if rule.FilterExpr != nil {
-			output, err := expr.Run(rule.FilterExpr, map[string]interface{}{
-				//"rules": rules, //is it still useful ?
-				"req": request,
-			})
+			output, err := expr.Run(rule.FilterExpr, GetHookEnv(*w, request))
 			if err != nil {
 				return fmt.Errorf("unable to run filter %s : %w", rule.Filter, err)
 			}
@@ -200,13 +237,7 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request ParsedRequest) error {
 		}
 		// here means there is no filter or the filter matched
 		for _, applyExpr := range rule.ApplyExpr {
-			_, err := expr.Run(applyExpr, map[string]interface{}{
-				"inband_rules":          w.InBandRules,
-				"outband_rules":         w.OutOfBandRules,
-				"req":                   request,
-				"RemoveInbandRuleByID":  w.RemoveInbandRuleByID,
-				"RemoveOutbandRuleByID": w.RemoveOutbandRuleByID,
-			})
+			_, err := expr.Run(applyExpr, GetHookEnv(*w, request))
 			if err != nil {
 				log.Errorf("unable to apply filter: %s", err)
 				continue
@@ -221,15 +252,37 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request ParsedRequest) error {
 add the helpers to:
  - remove by id-range
  - remove by tag
+ - set remediation by tag/id-range
 
 */
 
-func (w *WaapRuntimeConfig) RemoveInbandRuleByID(id int) {
-	w.InBandTx.RemoveRuleByIDWithError(id)
+func (w *WaapRuntimeConfig) RemoveInbandRuleByID(id int) error {
+	return w.InBandTx.RemoveRuleByIDWithError(id)
 }
 
-func (w *WaapRuntimeConfig) RemoveOutbandRuleByID(id int) {
-	w.OutOfBandTx.RemoveRuleByIDWithError(id)
+func (w *WaapRuntimeConfig) CancelEvent() error {
+	w.Response.SendEvent = false
+	return nil
+}
+
+func (w *WaapRuntimeConfig) SetActionnByID(id int, action string) error {
+	panic("not implemented")
+	return nil
+}
+
+func (w *WaapRuntimeConfig) RemoveOutbandRuleByID(id int) error {
+	return w.OutOfBandTx.RemoveRuleByIDWithError(id)
+}
+
+func (w *WaapRuntimeConfig) SetAction(action string) error {
+	w.Response.Action = action
+	return nil
+
+}
+
+func (w *WaapRuntimeConfig) SetHTTPCode(code int) error {
+	w.Response.HTTPResponseCode = code
+	return nil
 }
 
 func (w *WaapRuntimeConfig) ProcessInBandRules(request ParsedRequest) (*corazatypes.Interruption, error) {
@@ -257,3 +310,22 @@ func (w *WaapRuntimeConfig) ProcessOutOfBandRules(request ParsedRequest) (*coraz
 	}
 	return nil, nil
 }
+
+type BodyResponse struct {
+	Action     string `json:"action"`
+	HTTPStatus int    `json:"http_status"`
+}
+
+func (w *WaapRuntimeConfig) GenerateResponse(interrupted bool) (BodyResponse, error) {
+	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
+	}
+	resp.Action = w.Config.DefaultRemediation
+	resp.HTTPStatus = w.Config.BlockedHTTPCode
+
+	return resp, nil
+}

+ 0 - 9
pkg/waf/waf_helpers.go

@@ -30,12 +30,3 @@ func GetExprWAFOptions(ctx map[string]interface{}) []expr.Option {
 	}
 	return baseHelpers
 }
-
-func SetRulesToInband(params ...any) (any, error) {
-
-	return nil, nil
-}
-
-func SetRulesToOutOfBand(params ...any) (any, error) {
-	return nil, nil
-}