up
This commit is contained in:
parent
5a0b1b72d3
commit
1286efc74f
|
@ -1,31 +1,12 @@
|
||||||
Ongoing poc for Coraza
|
Ongoing poc for Coraza WAAP
|
||||||
|
|
||||||
For config:
|
# Configuration pieces
|
||||||
|
|
||||||
coraza_inband.conf:
|
## Acquisition
|
||||||
```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 example:
|
||||||
|
|
||||||
coraza_outofband.conf:
|
> `config/acquis.yaml` :
|
||||||
```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 :
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
listen_addr: 127.0.0.1
|
listen_addr: 127.0.0.1
|
||||||
|
@ -34,71 +15,38 @@ path: /
|
||||||
source: waf
|
source: waf
|
||||||
labels:
|
labels:
|
||||||
type: waf
|
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
|
```yaml
|
||||||
onsuccess: next_stage
|
name: mytest.yaml
|
||||||
debug: true
|
outofband_rules:
|
||||||
filter: "evt.Parsed.program == 'waf'"
|
- crowdsec/crs-default
|
||||||
name: crowdsecurity/waf-logs
|
inband_rules:
|
||||||
description: "Parse WAF logs"
|
- crowdsec/vpatch-default
|
||||||
statics:
|
default_remediation: block
|
||||||
- parsed: cloudtrail_parsed
|
variables_tracking:
|
||||||
expression: UnmarshalJSON(evt.Line.Raw, evt.Unmarshaled, 'waf')
|
- session_*
|
||||||
- meta: req_uuid
|
# onload:
|
||||||
expression: evt.Unmarshaled.waf.req_uuid
|
# - apply:
|
||||||
- meta: source_ip
|
# - DisabledInBandRuleByID(1003)
|
||||||
expression: evt.Unmarshaled.waf.source_ip
|
# pre_eval:
|
||||||
- meta: rule_id
|
# - filter: evt.SourceIP == '1.3.4.5'
|
||||||
expression: evt.Unmarshaled.waf.rule_id
|
# apply:
|
||||||
- meta: action
|
# - DisableOutOfBandRuleByID(2302)
|
||||||
expression: evt.Unmarshaled.waf.rule_action
|
|
||||||
- meta: service
|
|
||||||
value: waf
|
|
||||||
- parsed: event_type
|
|
||||||
value: waf_match
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
```yaml
|
||||||
type: trigger
|
cscli waf-rules install ...
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ type WaapSourceConfig struct {
|
||||||
Routines int `yaml:"routines"`
|
Routines int `yaml:"routines"`
|
||||||
Debug bool `yaml:"debug"`
|
Debug bool `yaml:"debug"`
|
||||||
WaapConfig string `yaml:"waap_config"`
|
WaapConfig string `yaml:"waap_config"`
|
||||||
|
WaapConfigPath string `yaml:"waap_config_path"`
|
||||||
configuration.DataSourceCommonCfg `yaml:",inline"`
|
configuration.DataSourceCommonCfg `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +119,24 @@ func (w *WaapSource) Configure(yamlConfig []byte, logger *log.Entry) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.InChan = make(chan waf.ParsedRequest)
|
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)
|
w.WaapRunners = make([]WaapRunner, wc.Routines)
|
||||||
|
|
||||||
for nbRoutine := 0; nbRoutine < wc.Routines; nbRoutine++ {
|
for nbRoutine := 0; nbRoutine < wc.Routines; nbRoutine++ {
|
||||||
|
|
|
@ -2,12 +2,14 @@ package waf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/antonmedv/expr"
|
"github.com/antonmedv/expr"
|
||||||
"github.com/antonmedv/expr/vm"
|
"github.com/antonmedv/expr/vm"
|
||||||
corazatypes "github.com/crowdsecurity/coraza/v3/types"
|
corazatypes "github.com/crowdsecurity/coraza/v3/types"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Hook struct {
|
type Hook struct {
|
||||||
|
@ -63,6 +65,19 @@ type WaapConfig struct {
|
||||||
VariablesTracking []string `yaml:"variables_tracking"`
|
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) {
|
func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
|
||||||
ret := &WaapRuntimeConfig{}
|
ret := &WaapRuntimeConfig{}
|
||||||
ret.Name = wc.Name
|
ret.Name = wc.Name
|
||||||
|
|
Loading…
Reference in a new issue