up
This commit is contained in:
parent
d3bb9f8ae1
commit
511468b8fe
5 changed files with 60 additions and 9 deletions
|
@ -149,6 +149,12 @@ func (w *WaapSource) Configure(yamlConfig []byte, logger *log.Entry) error {
|
|||
return fmt.Errorf("no waap_config provided")
|
||||
}
|
||||
|
||||
err = w.WaapRuntime.ProcessOnLoadRules()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to process on load rules : %s", err)
|
||||
}
|
||||
|
||||
w.WaapRunners = make([]WaapRunner, w.config.Routines)
|
||||
|
||||
for nbRoutine := 0; nbRoutine < w.config.Routines; nbRoutine++ {
|
||||
|
|
|
@ -186,6 +186,35 @@ func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) ProcessOnLoadRules() error {
|
||||
for _, rule := range w.CompiledOnMatch {
|
||||
if rule.FilterExpr != nil {
|
||||
output, err := expr.Run(rule.FilterExpr, GetHookEnv(w, ParsedRequest{}))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to run filter %s : %w", rule.Filter, err)
|
||||
}
|
||||
switch t := output.(type) {
|
||||
case bool:
|
||||
if !t {
|
||||
log.Infof("filter didnt match")
|
||||
continue
|
||||
}
|
||||
default:
|
||||
log.Errorf("Filter must return a boolean, can't filter")
|
||||
continue
|
||||
}
|
||||
}
|
||||
for _, applyExpr := range rule.ApplyExpr {
|
||||
_, err := expr.Run(applyExpr, GetHookEnv(w, ParsedRequest{}))
|
||||
if err != nil {
|
||||
log.Errorf("unable to apply filter: %s", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WaapRuntimeConfig) ProcessOnMatchRules(request ParsedRequest) error {
|
||||
|
||||
for _, rule := range w.CompiledOnMatch {
|
||||
|
|
|
@ -3,6 +3,7 @@ package waf
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type VPatchRule struct {
|
||||
|
@ -17,8 +18,6 @@ type VPatchRule struct {
|
|||
Detect string `yaml:"detect"` //@detectXSS, @detectSQLi, etc
|
||||
Logic string `yaml:"logic,omitempty"` // "AND", "OR", or empty if not applicable
|
||||
SubRules []VPatchRule `yaml:"sub_rules,omitempty"`
|
||||
|
||||
id int
|
||||
}
|
||||
|
||||
func (v *VPatchRule) String() string {
|
||||
|
@ -46,26 +45,21 @@ func (v *VPatchRule) constructRule(depth int) string {
|
|||
|
||||
switch v.Logic {
|
||||
case "AND":
|
||||
// Add "chain" to the current rule
|
||||
result = strings.TrimSuffix(result, `"`) + `,chain"` + "\n"
|
||||
for _, subRule := range v.SubRules {
|
||||
result += subRule.constructRule(depth + 1)
|
||||
}
|
||||
case "OR":
|
||||
skips := countTotalRules(v.SubRules) - 1
|
||||
// If the "OR" rule is at the top level and is followed by any rule, we need to count that too
|
||||
if depth == 0 {
|
||||
skips++ // For the current rule
|
||||
skips++
|
||||
}
|
||||
// Add the skip directive to the current rule too
|
||||
result = strings.TrimSuffix(result, `"`) + fmt.Sprintf(`,skip:%d"`+"\n", skips)
|
||||
for _, subRule := range v.SubRules {
|
||||
skips--
|
||||
if skips > 0 {
|
||||
// Append skip directive and decrease the skip count
|
||||
result += strings.TrimSuffix(subRule.singleRuleString(), `"`) + fmt.Sprintf(`,skip:%d"`+"\n", skips)
|
||||
} else {
|
||||
// If no skip is required, append only a newline
|
||||
result += subRule.singleRuleString() + "\n"
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +85,9 @@ func (v *VPatchRule) singleRuleString() string {
|
|||
ruleStr = fmt.Sprintf(`SecRule %s "%s"`, v.Target, operator)
|
||||
}
|
||||
|
||||
actions := fmt.Sprintf(` "id:%d,deny,log`, v.id)
|
||||
//FIXME: phase2 should probably not be hardcoded
|
||||
//Find a better way than using time.Now().UnixMilli() to generate a unique ID
|
||||
actions := fmt.Sprintf(` "id:%d,deny,log,phase:2`, time.Now().UnixNano())
|
||||
|
||||
// Handle transformation
|
||||
if v.Transform != "" {
|
||||
|
|
|
@ -33,6 +33,25 @@ func TestVPatchRuleString(t *testing.T) {
|
|||
},
|
||||
},
|
||||
expected: `SecRule ARGS:bar "@rx [0-9]" "id:0,deny,log,chain"
|
||||
SecRule REQUEST_URI "@rx /joomla/index.php/component/users/" "id:0,deny,log"`,
|
||||
},
|
||||
{
|
||||
name: "AND Logic Rule",
|
||||
rule: VPatchRule{
|
||||
Logic: "AND",
|
||||
SubRules: []VPatchRule{
|
||||
{
|
||||
Target: "REQUEST_URI",
|
||||
Match: "/joomla/index.php/component/users/",
|
||||
},
|
||||
{
|
||||
Target: "ARGS",
|
||||
Variable: "bar",
|
||||
Match: "[0-9]",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: `SecRule ARGS:bar "@rx [0-9]" "id:0,deny,log,chain"
|
||||
SecRule REQUEST_URI "@rx /joomla/index.php/component/users/" "id:0,deny,log"`,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ type WaapCollectionConfig struct {
|
|||
SecLangFilesRules []string `yaml:"seclang_files_rules"`
|
||||
SecLangRules []string `yaml:"seclang_rules"`
|
||||
Rules []VPatchRule `yaml:"rules"`
|
||||
Data interface{} `yaml:"data"` //Ignore it
|
||||
}
|
||||
|
||||
func LoadCollection(collection string) (WaapCollection, error) {
|
||||
|
|
Loading…
Reference in a new issue