Creating scenarios
All the examples assume that you have installed the iptables parser, and that your iptables configuration logs dropped packets.
Leaky bucket
In this example, we will write a simple scenario based on a leaky bucket that will trigger if an IP tries to port scan our machine.
We'll start with the most basic scenario:
type: leaky
debug: true
name: demo/leaky-example
description: "detect cool stuff"
filter: evt.Meta.log_type == 'iptables_drop'
capacity: 1
leakspeed: 1m
blackhole: 1m
labels:
type: scan
We define:
- A filter: an expression that decides if the scenario will apply to current event or not
- A type: here, we have a
leaky
bucket - A capacity: how many events can be poured in the bucket before it overflows
- A leakspeed: the speed at which events are removed from the bucket
- A blackhole: duration for which the bucket should be overflow again
- Some labels to qualify the event
This scenario in its current state is not really useful:
- We do not define a
groupby
: the same bucket will be used for all source IP, which prevent us to ban the IP actually doing the port scan. - Our filter is too generic: we also match dropped UDP packets, and it can be very dangerous to apply a decision on them.
Let's fix that !
type: leaky
debug: true
name: demo/leaky-example
description: "detect cool stuff"
filter: "evt.Meta.log_type == 'iptables_drop' and evt.Parsed.proto == 'TCP'"
groupby: evt.Meta.source_ip
capacity: 15
leakspeed: 1m
blackhole: 1m
labels:
type: scan
We added:
A new filter,
and evt.Parsed.proto == 'TCP'
: our scenario will now only apply if the protocol is TCP (based on what was extracted from the log line by our GROK pattern)A
groupby
parameter: we now create one bucket per source ipWe also updated the capacity and leakspeed to be more useful for a real life scenario.
But this is still not perfect ! We want to create a scenario to detect port scan, but our current configuration will also detect repeated connections to the same port.
We can fix this by adding a
distinct
parameter:
type: leaky
debug: true
name: demo/leaky-example
description: "detect cool stuff"
filter: "evt.Meta.log_type == 'iptables_drop' and evt.Parsed.proto == 'TCP'"
groupby: evt.Meta.source_ip
distinct: evt.Parsed.dst_port
capacity: 15
leakspeed: 1m
blackhole: 1m
labels:
type: scan
The distinct parameter will prevent an event to be poured into the bucket if there is already an event in it with the same value for evt.Parsed.dst_port
.
In our case, this means that we will only have unique ports in our bucket.
And voila ! We now have a working scenario able to detect port scanning.
Trigger bucket
In this example, we will write a simple scenario that will trigger if anyone sends a packet to the port 3389.
type: trigger
name: demo/trigger-example
description: "Detect connection to RDP port"
filter: "evt.Meta.log_type == 'iptables_drop' and evt.Parsed.proto == 'TCP' and evt.Parsed.dst_port == '3389'"
groupby: evt.Meta.source_ip
blackhole: 2m
labels:
service: rdp
type: scan
remediation: true
What changed in comparaison to our leaky example ?
- We defined the type to be
trigger
: this means that the bucket will overflow if any event is poured into it - Our filter checks if the value of
dst_port
is equal to3389
: you can access all capture group defined in a GROK pattern with the objectevt.Parsed
- We set the
remediation
label totrue
: if the bucket overflow, we will apply a remediation based on your profile configuration (by default, 4h ban)
Let's try it !
Put the scenario in a file called iptables-rdp.yaml
, in the scenarios
folder of crowdsec.
Use cscli
to make sure the scenario is detected:
$ cscli scenarios list
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NAME 📦 STATUS VERSION LOCAL PATH
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
iptables-rdp.yaml 🏠 enabled,local /etc/crowdsec/scenarios/iptables-rdp.yaml
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Next, we will trigger the scenario by attempting to connect to the port 3389 on the machine where crowdsec is running:
$ nc -v 127.0.0.1 3389
nc: connect to 127.0.0.1 port 3389 (tcp) failed: Connection refused
In our kernel logs, we can see:
Aug 20 16:20:09 mantis kernel: [887475.435839] DROP: IN=lo OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:08:00 SRC=192.168.1.23 DST=192.168.1.23 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=29037 DF PROTO=TCP SPT=39158 DPT=3389 WINDOW=65495 RES=0x00 SYN URGP=0
We can then check that a decision has been applied:
$ cscli decisions list
+-------+----------+-----------------+----------------------+--------+---------+----+--------+------------------+----------+
| ID | SOURCE | SCOPE:VALUE | REASON | ACTION | COUNTRY | AS | EVENTS | EXPIRATION | ALERT ID |
+-------+----------+-----------------+----------------------+--------+---------+----+--------+------------------+----------+
| 17563 | crowdsec | Ip:192.168.1.47 | demo/trigger-example | ban | | | 1 | 3h59m5.00140614s | 82 |
+-------+----------+-----------------+----------------------+--------+---------+----+--------+------------------+----------+