github.com/crowdsecurity/crowdsec@v1.6.1/pkg/acquisition/modules/appsec/rx_operator.go (about) 1 package appsecacquisition 2 3 import ( 4 "fmt" 5 "strconv" 6 "unicode/utf8" 7 8 "github.com/crowdsecurity/coraza/v3/experimental/plugins" 9 "github.com/crowdsecurity/coraza/v3/experimental/plugins/plugintypes" 10 "github.com/wasilibs/go-re2" 11 "github.com/wasilibs/go-re2/experimental" 12 ) 13 14 type rx struct { 15 re *re2.Regexp 16 } 17 18 var _ plugintypes.Operator = (*rx)(nil) 19 20 func newRX(options plugintypes.OperatorOptions) (plugintypes.Operator, error) { 21 // (?sm) enables multiline mode which makes 942522-7 work, see 22 // - https://stackoverflow.com/a/27680233 23 // - https://groups.google.com/g/golang-nuts/c/jiVdamGFU9E 24 data := fmt.Sprintf("(?sm)%s", options.Arguments) 25 26 var re *re2.Regexp 27 var err error 28 29 if matchesArbitraryBytes(data) { 30 re, err = experimental.CompileLatin1(data) 31 } else { 32 re, err = re2.Compile(data) 33 } 34 if err != nil { 35 return nil, err 36 } 37 return &rx{re: re}, nil 38 } 39 40 func (o *rx) Evaluate(tx plugintypes.TransactionState, value string) bool { 41 if tx.Capturing() { 42 match := o.re.FindStringSubmatch(value) 43 if len(match) == 0 { 44 return false 45 } 46 for i, c := range match { 47 if i == 9 { 48 return true 49 } 50 tx.CaptureField(i, c) 51 } 52 return true 53 } else { 54 return o.re.MatchString(value) 55 } 56 } 57 58 // RegisterRX registers the rx operator using a WASI implementation instead of Go. 59 func RegisterRX() { 60 plugins.RegisterOperator("rx", newRX) 61 } 62 63 // matchesArbitraryBytes checks for control sequences for byte matches in the expression. 64 // If the sequences are not valid utf8, it returns true. 65 func matchesArbitraryBytes(expr string) bool { 66 decoded := make([]byte, 0, len(expr)) 67 for i := 0; i < len(expr); i++ { 68 c := expr[i] 69 if c != '\\' { 70 decoded = append(decoded, c) 71 continue 72 } 73 if i+3 >= len(expr) { 74 decoded = append(decoded, expr[i:]...) 75 break 76 } 77 if expr[i+1] != 'x' { 78 decoded = append(decoded, expr[i]) 79 continue 80 } 81 82 v, mb, _, err := strconv.UnquoteChar(expr[i:], 0) 83 if err != nil || mb { 84 // Wasn't a byte escape sequence, shouldn't happen in practice. 85 decoded = append(decoded, expr[i]) 86 continue 87 } 88 89 decoded = append(decoded, byte(v)) 90 i += 3 91 } 92 93 return !utf8.Valid(decoded) 94 }