2023-09-11 08:35:14 +00:00
|
|
|
package waf
|
|
|
|
|
2023-09-14 07:39:24 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"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"
|
|
|
|
"github.com/crowdsecurity/crowdsec/pkg/cwhub"
|
2023-10-25 16:45:49 +00:00
|
|
|
"github.com/crowdsecurity/crowdsec/pkg/waf/waap_rule"
|
2023-09-14 07:39:24 +00:00
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
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-09-11 08:35:14 +00:00
|
|
|
func LoadCollection(collection string) (WaapCollection, error) {
|
2023-09-14 07:39:24 +00:00
|
|
|
|
|
|
|
//FIXME: do it once globally
|
2023-09-14 09:18:33 +00:00
|
|
|
waapRules := make(map[string]WaapCollectionConfig)
|
|
|
|
|
2023-10-19 12:19:37 +00:00
|
|
|
hub, err := cwhub.GetHub()
|
|
|
|
if err != nil {
|
|
|
|
return WaapCollection{}, fmt.Errorf("unable to load hub : %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, hubWafRuleItem := range hub.GetItemMap(cwhub.WAAP_RULES) {
|
2023-10-23 08:54:26 +00:00
|
|
|
//log.Infof("loading %s", hubWafRuleItem.LocalPath)
|
2023-09-14 07:39:24 +00:00
|
|
|
if !hubWafRuleItem.Installed {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
content, err := os.ReadFile(hubWafRuleItem.LocalPath)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("unable to read file %s : %s", hubWafRuleItem.LocalPath, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
var rule WaapCollectionConfig
|
|
|
|
|
2023-10-17 07:32:40 +00:00
|
|
|
err = yaml.UnmarshalStrict(content, &rule)
|
2023-09-14 07:39:24 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("unable to unmarshal file %s : %s", hubWafRuleItem.LocalPath, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-10-18 15:11:43 +00:00
|
|
|
if rule.Type != WAAP_RULE { //FIXME: rename to waap-rule when hub is properly updated
|
|
|
|
log.Warnf("unexpected type %s instead of %s for file %s", rule.Type, WAAP_RULE, hubWafRuleItem.LocalPath)
|
2023-09-14 07:39:24 +00:00
|
|
|
continue
|
|
|
|
}
|
2023-10-27 09:10:17 +00:00
|
|
|
|
|
|
|
rule.hash = hubWafRuleItem.LocalHash
|
|
|
|
rule.version = hubWafRuleItem.Version
|
|
|
|
|
2023-09-14 09:18:33 +00:00
|
|
|
log.Infof("Adding %s to waap rules", rule.Name)
|
2023-10-27 09:08:54 +00:00
|
|
|
// if rule.Debug {
|
|
|
|
// log.Infof("Enabling debug for collection %s", rule.Name)
|
|
|
|
|
|
|
|
// //SetRuleDebug(rule.ID, true)
|
|
|
|
// }
|
2023-09-14 07:39:24 +00:00
|
|
|
waapRules[rule.Name] = rule
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(waapRules) == 0 {
|
|
|
|
return WaapCollection{}, fmt.Errorf("no waap rules found in hub")
|
|
|
|
}
|
|
|
|
|
|
|
|
var loadedRule WaapCollectionConfig
|
2023-09-14 09:18:33 +00:00
|
|
|
var ok bool
|
2023-09-14 07:39:24 +00:00
|
|
|
|
2023-09-14 09:18:33 +00:00
|
|
|
if loadedRule, ok = waapRules[collection]; !ok {
|
2023-09-14 07:39:24 +00:00
|
|
|
return WaapCollection{}, fmt.Errorf("no waap rules found for collection %s", collection)
|
|
|
|
}
|
|
|
|
|
2023-10-17 07:32:40 +00:00
|
|
|
log.Infof("Found rule collection %s with %+v", loadedRule.Name, loadedRule)
|
|
|
|
|
2023-09-14 09:18:33 +00:00
|
|
|
waapCol := WaapCollection{
|
2023-09-14 07:39:24 +00:00
|
|
|
collectionName: loadedRule.Name,
|
2023-09-14 09:18:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if loadedRule.SecLangFilesRules != nil {
|
|
|
|
for _, rulesFile := range loadedRule.SecLangFilesRules {
|
2023-10-19 12:19:37 +00:00
|
|
|
fullPath := filepath.Join(hub.GetDataDir(), rulesFile)
|
2023-09-14 09:18:33 +00:00
|
|
|
c, err := os.ReadFile(fullPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to read file %s : %s", rulesFile, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, line := range strings.Split(string(c), "\n") {
|
|
|
|
if strings.HasPrefix(line, "#") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if strings.TrimSpace(line) == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
waapCol.Rules = append(waapCol.Rules, line)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if loadedRule.SecLangRules != nil {
|
|
|
|
waapCol.Rules = append(waapCol.Rules, loadedRule.SecLangRules...)
|
|
|
|
}
|
|
|
|
|
2023-10-17 07:32:40 +00:00
|
|
|
if loadedRule.Rules != nil {
|
|
|
|
for _, rule := range loadedRule.Rules {
|
2023-10-27 09:10:17 +00:00
|
|
|
strRule, ruleId, err := rule.Convert(waap_rule.ModsecurityRuleType, loadedRule.Name)
|
2023-10-25 16:45:49 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Errorf("unable to convert rule %s : %s", rule.Name, err)
|
|
|
|
return WaapCollection{}, err
|
|
|
|
}
|
|
|
|
log.Infof("Adding rule %s", strRule)
|
|
|
|
waapCol.Rules = append(waapCol.Rules, strRule)
|
2023-10-27 09:10:17 +00:00
|
|
|
|
|
|
|
if _, ok := WaapRulesDetails[int(ruleId)]; !ok {
|
|
|
|
WaapRulesDetails[int(ruleId)] = RulesDetails{
|
|
|
|
LogLevel: log.InfoLevel,
|
|
|
|
Hash: loadedRule.hash,
|
|
|
|
Version: loadedRule.version,
|
|
|
|
Name: loadedRule.Name,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Warnf("conflicting id %d for rule %s !", ruleId, rule.Name)
|
|
|
|
}
|
2023-10-17 07:32:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-14 09:18:33 +00:00
|
|
|
return waapCol, 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
|
|
|
|
}
|