diff --git a/pkg/appsec/appsec_rule/modsec_rule_test.go b/pkg/appsec/appsec_rule/modsec_rule_test.go index a11bfd214c8..88b1e469ca8 100644 --- a/pkg/appsec/appsec_rule/modsec_rule_test.go +++ b/pkg/appsec/appsec_rule/modsec_rule_test.go @@ -8,6 +8,16 @@ func TestVPatchRuleString(t *testing.T) { rule CustomRule expected string }{ + { + name: "Collection count", + rule: CustomRule{ + Zones: []string{"ARGS"}, + Variables: []string{"foo"}, + Match: match{Type: "eq", Value: "1"}, + Transform: []string{"count"}, + }, + expected: `SecRule &ARGS_GET:foo "@eq 1" "id:853070236,phase:2,deny,log,msg:'Collection count',tag:'crowdsec-Collection count'"`, + }, { name: "Base Rule", rule: CustomRule{ diff --git a/pkg/appsec/appsec_rule/modsecurity.go b/pkg/appsec/appsec_rule/modsecurity.go index e9f131b5f6e..064b7543f2e 100644 --- a/pkg/appsec/appsec_rule/modsecurity.go +++ b/pkg/appsec/appsec_rule/modsecurity.go @@ -122,6 +122,16 @@ func (m *ModsecurityRule) buildRules(rule *CustomRule, appsecRuleName string, an return ret, nil } + zone_prefix := "" + variable_prefix := "" + if rule.Transform != nil { + for tidx, transform := range rule.Transform { + if transform == "count" { + zone_prefix = "&" + rule.Transform[tidx] = "" + } + } + } for idx, zone := range rule.Zones { mappedZone, ok := zonesMap[zone] if !ok { @@ -134,7 +144,7 @@ func (m *ModsecurityRule) buildRules(rule *CustomRule, appsecRuleName string, an if idx > 0 || j > 0 { r.WriteByte('|') } - r.WriteString(fmt.Sprintf("%s:%s", mappedZone, variable)) + r.WriteString(fmt.Sprintf("%s%s:%s%s", zone_prefix, mappedZone, variable_prefix, variable)) } } } @@ -157,6 +167,9 @@ func (m *ModsecurityRule) buildRules(rule *CustomRule, appsecRuleName string, an if rule.Transform != nil { for _, transform := range rule.Transform { + if transform == "" { + continue + } r.WriteByte(',') if mappedTransform, ok := transformMap[transform]; ok { r.WriteString(mappedTransform)