2023-09-11 08:35:14 +00:00
|
|
|
package waf
|
|
|
|
|
2023-09-14 07:39:24 +00:00
|
|
|
import (
|
|
|
|
"os"
|
2023-09-14 09:18:33 +00:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2023-09-14 07:39:24 +00:00
|
|
|
|
|
|
|
corazatypes "github.com/crowdsecurity/coraza/v3/types"
|
2023-10-25 16:45:49 +00:00
|
|
|
"github.com/crowdsecurity/crowdsec/pkg/waf/waap_rule"
|
2023-09-14 07:39:24 +00:00
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
)
|
2023-09-11 08:35:14 +00:00
|
|
|
|
|
|
|
// to be filled w/ seb update
|
|
|
|
type WaapCollection struct {
|
2023-09-14 07:39:24 +00:00
|
|
|
collectionName string
|
2023-09-14 09:18:33 +00:00
|
|
|
Rules []string
|
2023-09-11 08:35:14 +00:00
|
|
|
}
|
|
|
|
|
2023-10-18 15:11:43 +00:00
|
|
|
var WAAP_RULE = "waap-rule"
|
|
|
|
|
2023-09-11 08:35:14 +00:00
|
|
|
// to be filled w/ seb update
|
|
|
|
type WaapCollectionConfig struct {
|
2023-10-25 16:45:49 +00:00
|
|
|
Type string `yaml:"type"`
|
|
|
|
Name string `yaml:"name"`
|
2023-10-27 09:08:54 +00:00
|
|
|
Debug bool `yaml:"debug"`
|
2023-10-25 16:45:49 +00:00
|
|
|
Description string `yaml:"description"`
|
|
|
|
SecLangFilesRules []string `yaml:"seclang_files_rules"`
|
|
|
|
SecLangRules []string `yaml:"seclang_rules"`
|
|
|
|
Rules []waap_rule.CustomRule `yaml:"rules"`
|
2023-10-27 09:10:17 +00:00
|
|
|
|
2023-11-15 14:08:57 +00:00
|
|
|
Labels map[string]interface{} `yaml:"labels"` //Labels is K:V list aiming at providing context the overflow
|
|
|
|
|
2023-10-27 09:10:17 +00:00
|
|
|
Data interface{} `yaml:"data"` //Ignore it
|
|
|
|
hash string `yaml:"-"`
|
|
|
|
version string `yaml:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type RulesDetails struct {
|
|
|
|
LogLevel log.Level
|
|
|
|
Hash string
|
|
|
|
Version string
|
|
|
|
Name string
|
2023-09-11 08:35:14 +00:00
|
|
|
}
|
|
|
|
|
2023-10-27 09:10:17 +00:00
|
|
|
// Should it be a global ?
|
|
|
|
// Is using the id is a good idea ? might be too specific to coraza and not easily reusable
|
|
|
|
var WaapRulesDetails = make(map[int]RulesDetails)
|
|
|
|
|
2023-11-08 20:14:03 +00:00
|
|
|
func LoadCollection(pattern string) ([]WaapCollection, error) {
|
|
|
|
ret := make([]WaapCollection, 0)
|
2023-09-14 07:39:24 +00:00
|
|
|
|
2023-11-08 20:14:03 +00:00
|
|
|
for _, waapRule := range waapRules {
|
2023-09-14 07:39:24 +00:00
|
|
|
|
2023-11-08 20:14:03 +00:00
|
|
|
matched, err := filepath.Match(pattern, waapRule.Name)
|
2023-09-14 09:18:33 +00:00
|
|
|
|
2023-11-08 20:14:03 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to match %s with %s : %s", waapRule.Name, pattern, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !matched {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
waapCol := WaapCollection{
|
|
|
|
collectionName: waapRule.Name,
|
|
|
|
}
|
|
|
|
|
|
|
|
if waapRule.SecLangFilesRules != nil {
|
|
|
|
for _, rulesFile := range waapRule.SecLangFilesRules {
|
|
|
|
fullPath := filepath.Join(hub.GetDataDir(), rulesFile)
|
|
|
|
c, err := os.ReadFile(fullPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to read file %s : %s", rulesFile, err)
|
2023-09-14 09:18:33 +00:00
|
|
|
continue
|
|
|
|
}
|
2023-11-08 20:14:03 +00:00
|
|
|
for _, line := range strings.Split(string(c), "\n") {
|
|
|
|
if strings.HasPrefix(line, "#") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if strings.TrimSpace(line) == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
waapCol.Rules = append(waapCol.Rules, line)
|
2023-09-14 09:18:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-08 20:14:03 +00:00
|
|
|
if waapRule.SecLangRules != nil {
|
|
|
|
waapCol.Rules = append(waapCol.Rules, waapRule.SecLangRules...)
|
|
|
|
}
|
2023-09-14 09:18:33 +00:00
|
|
|
|
2023-11-08 20:14:03 +00:00
|
|
|
if waapRule.Rules != nil {
|
|
|
|
for _, rule := range waapRule.Rules {
|
|
|
|
strRule, rulesId, err := rule.Convert(waap_rule.ModsecurityRuleType, waapRule.Name)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to convert rule %s : %s", rule.Name, err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
log.Infof("Adding rule %s", strRule)
|
|
|
|
waapCol.Rules = append(waapCol.Rules, strRule)
|
|
|
|
|
|
|
|
//We only take the first id, as it's the one of the "main" rule
|
|
|
|
if _, ok := WaapRulesDetails[int(rulesId[0])]; !ok {
|
|
|
|
WaapRulesDetails[int(rulesId[0])] = RulesDetails{
|
|
|
|
LogLevel: log.InfoLevel,
|
|
|
|
Hash: waapRule.hash,
|
|
|
|
Version: waapRule.version,
|
|
|
|
Name: waapRule.Name,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Warnf("conflicting id %d for rule %s !", rulesId[0], rule.Name)
|
2023-10-27 09:10:17 +00:00
|
|
|
}
|
2023-10-27 09:17:27 +00:00
|
|
|
|
2023-11-08 20:14:03 +00:00
|
|
|
for _, id := range rulesId {
|
|
|
|
SetRuleDebug(int(id), waapRule.Debug)
|
|
|
|
}
|
2023-10-27 09:10:17 +00:00
|
|
|
}
|
2023-10-17 07:32:40 +00:00
|
|
|
}
|
2023-11-08 20:14:03 +00:00
|
|
|
ret = append(ret, waapCol)
|
2023-10-17 07:32:40 +00:00
|
|
|
}
|
2023-11-08 20:14:03 +00:00
|
|
|
return ret, nil
|
2023-09-11 08:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (wcc WaapCollectionConfig) LoadCollection(collection string) (WaapCollection, error) {
|
|
|
|
return WaapCollection{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w WaapCollection) Check() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w WaapCollection) Eval(req ParsedRequest) (*corazatypes.Interruption, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w WaapCollection) GetDisplayName() string {
|
2023-09-14 07:39:24 +00:00
|
|
|
return w.collectionName
|
2023-09-11 08:35:14 +00:00
|
|
|
}
|
2023-09-19 11:16:33 +00:00
|
|
|
|
|
|
|
func (w WaapCollection) String() string {
|
|
|
|
ret := ""
|
|
|
|
for _, rule := range w.Rules {
|
|
|
|
ret += rule + "\n"
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|