up
This commit is contained in:
parent
5a0b1b72d3
commit
1286efc74f
3 changed files with 66 additions and 84 deletions
|
@ -1,31 +1,12 @@
|
|||
Ongoing poc for Coraza
|
||||
Ongoing poc for Coraza WAAP
|
||||
|
||||
For config:
|
||||
# Configuration pieces
|
||||
|
||||
coraza_inband.conf:
|
||||
```shell
|
||||
SecRuleEngine On
|
||||
SecRule ARGS:id "@eq 0" "id:1, phase:1,deny, status:403,msg:'Invalid id',log,auditlog"
|
||||
SecRequestBodyAccess On
|
||||
SecRule REQUEST_BODY "@contains password" "id:2, phase:2,deny, status:403,msg:'Invalid request body',log,auditlog"
|
||||
```
|
||||
## Acquisition
|
||||
|
||||
acquisition example:
|
||||
|
||||
coraza_outofband.conf:
|
||||
```shell
|
||||
SecRuleEngine On
|
||||
SecRule ARGS:id "@eq 1" "id:3,phase:1,log,msg:'Invalid id',log,auditlog"
|
||||
SecRule ARGS:idd "@eq 2" "id:4,phase:1,log,msg:'Invalid id',log,auditlog"
|
||||
SecRequestBodyAccess On
|
||||
#We know that because we are not cloning the body in waf.go, the outofband rules cannot access body as it has been consumed.
|
||||
#We are finding a way around this
|
||||
#SecRule REQUEST_BODY "@contains totolol" "id:4, phase:2,deny,msg:'Invalid request body',log,auditlog"
|
||||
#SecRule REQUEST_BODY "@contains password" "id:2, phase:2,deny, status:403,msg:'Invalid request body',log,auditlog"
|
||||
|
||||
```
|
||||
|
||||
|
||||
acquis.yaml :
|
||||
> `config/acquis.yaml` :
|
||||
|
||||
```yaml
|
||||
listen_addr: 127.0.0.1
|
||||
|
@ -34,71 +15,38 @@ path: /
|
|||
source: waf
|
||||
labels:
|
||||
type: waf
|
||||
#routines: 1
|
||||
waap_config: mytest
|
||||
```
|
||||
|
||||
Coraza parser:
|
||||
## Waap config
|
||||
|
||||
The waap config defines what rules that will be loaded by a given waap engine (associated with an acquis).
|
||||
|
||||
> `config/waap_configs/mytest.yaml`
|
||||
|
||||
```yaml
|
||||
onsuccess: next_stage
|
||||
debug: true
|
||||
filter: "evt.Parsed.program == 'waf'"
|
||||
name: crowdsecurity/waf-logs
|
||||
description: "Parse WAF logs"
|
||||
statics:
|
||||
- parsed: cloudtrail_parsed
|
||||
expression: UnmarshalJSON(evt.Line.Raw, evt.Unmarshaled, 'waf')
|
||||
- meta: req_uuid
|
||||
expression: evt.Unmarshaled.waf.req_uuid
|
||||
- meta: source_ip
|
||||
expression: evt.Unmarshaled.waf.source_ip
|
||||
- meta: rule_id
|
||||
expression: evt.Unmarshaled.waf.rule_id
|
||||
- meta: action
|
||||
expression: evt.Unmarshaled.waf.rule_action
|
||||
- meta: service
|
||||
value: waf
|
||||
- parsed: event_type
|
||||
value: waf_match
|
||||
|
||||
name: mytest.yaml
|
||||
outofband_rules:
|
||||
- crowdsec/crs-default
|
||||
inband_rules:
|
||||
- crowdsec/vpatch-default
|
||||
default_remediation: block
|
||||
variables_tracking:
|
||||
- session_*
|
||||
# onload:
|
||||
# - apply:
|
||||
# - DisabledInBandRuleByID(1003)
|
||||
# pre_eval:
|
||||
# - filter: evt.SourceIP == '1.3.4.5'
|
||||
# apply:
|
||||
# - DisableOutOfBandRuleByID(2302)
|
||||
```
|
||||
|
||||
Coraza trigger scenario:
|
||||
# Waap Rules
|
||||
|
||||
For the above two to work, we need to have the two refered waap collection installed : `crowdsec/crs-default` and `crowdsec/vpatch-default`. You need to set hub_branch to ...
|
||||
|
||||
```yaml
|
||||
type: trigger
|
||||
filter: evt.Parsed.event_type == "waf_match" && evt.Unmarshaled.waf.rule_type == "inband"
|
||||
debug: true
|
||||
name: coroza-triggger
|
||||
description: here we go
|
||||
blackhole: 2m
|
||||
labels:
|
||||
type: exploit
|
||||
remediation: true
|
||||
groupby: "evt.Meta.source_ip"
|
||||
```
|
||||
|
||||
Coraza leaky scenario:
|
||||
|
||||
```yaml
|
||||
type: leaky
|
||||
filter: evt.Parsed.event_type == "waf_match" && evt.Unmarshaled.waf.rule_type == "outofband"
|
||||
debug: true
|
||||
name: coroza-leaky
|
||||
description: here we go
|
||||
blackhole: 2m
|
||||
leakspeed: 30s
|
||||
capacity: 1
|
||||
labels:
|
||||
type: exploit
|
||||
remediation: true
|
||||
groupby: "evt.Meta.source_ip"
|
||||
distinct: evt.Meta.rule_id
|
||||
```
|
||||
|
||||
|
||||
|
||||
To be solved:
|
||||
- We need to solve the body cloning issue
|
||||
- Merge w/ hub
|
||||
|
||||
|
||||
cscli waf-rules install ...
|
||||
```
|
|
@ -34,6 +34,7 @@ type WaapSourceConfig struct {
|
|||
Routines int `yaml:"routines"`
|
||||
Debug bool `yaml:"debug"`
|
||||
WaapConfig string `yaml:"waap_config"`
|
||||
WaapConfigPath string `yaml:"waap_config_path"`
|
||||
configuration.DataSourceCommonCfg `yaml:",inline"`
|
||||
}
|
||||
|
||||
|
@ -118,6 +119,24 @@ func (w *WaapSource) Configure(yamlConfig []byte, logger *log.Entry) error {
|
|||
}
|
||||
|
||||
w.InChan = make(chan waf.ParsedRequest)
|
||||
|
||||
//let's load the associated waap_config:
|
||||
if wc.WaapConfigPath != "" {
|
||||
return fmt.Errorf("resolution gor waap_config not implemented yet")
|
||||
} else if wc.WaapConfig != "" {
|
||||
waapCfg := waf.WaapConfig{}
|
||||
err := waapCfg.Load(wc.WaapConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load waap_config : %s", err)
|
||||
}
|
||||
w.WaapRuntime, err = waapCfg.Build()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to build waap_config : %s", err)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("no waap_config provided")
|
||||
}
|
||||
|
||||
w.WaapRunners = make([]WaapRunner, wc.Routines)
|
||||
|
||||
for nbRoutine := 0; nbRoutine < wc.Routines; nbRoutine++ {
|
||||
|
|
|
@ -2,12 +2,14 @@ package waf
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"github.com/antonmedv/expr"
|
||||
"github.com/antonmedv/expr/vm"
|
||||
corazatypes "github.com/crowdsecurity/coraza/v3/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type Hook struct {
|
||||
|
@ -63,6 +65,19 @@ type WaapConfig struct {
|
|||
VariablesTracking []string `yaml:"variables_tracking"`
|
||||
}
|
||||
|
||||
func (wc *WaapConfig) Load(file string) error {
|
||||
yamlFile, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read file %s : %s", file, err)
|
||||
}
|
||||
err = yaml.UnmarshalStrict(yamlFile, wc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to parse yaml file %s : %s", file, err)
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
|
||||
ret := &WaapRuntimeConfig{}
|
||||
ret.Name = wc.Name
|
||||
|
|
Loading…
Add table
Reference in a new issue