Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .tests/bitwarden-slow-bf/bitwarden-slow-bf.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
2023-04-24 10:00:00.000 -05:00 [WRN] Failed login attempt. 192.168.1.100
2023-04-24 10:03:00.000 -05:00 [WRN] Failed login attempt. 192.168.1.100
2023-04-24 10:06:00.000 -05:00 [WRN] Failed login attempt. 192.168.1.100
2023-04-24 10:20:00.000 -05:00 [WRN] Failed login attempt. 192.168.1.101
2023-04-24 10:40:00.000 -05:00 [WRN] Failed login attempt. 192.168.1.101
2023-04-24 11:00:00.000 -05:00 [WRN] Failed login attempt. 192.168.1.101

16 changes: 16 additions & 0 deletions .tests/bitwarden-slow-bf/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
parsers:
- crowdsecurity/syslog-logs
- crowdsecurity/dateparse-enrich
- ./parsers/s01-parse/MariuszKociubinski/bitwarden-logs.yaml
scenarios:
- ./scenarios/crowdsecurity/bitwarden-slow-bf.yaml
# we put this one on purpose : we want only to trigger the slow-bf
- ./scenarios/MariuszKociubinski/bitwarden-bf.yaml
postoverflows:
- ""
log_file: bitwarden-slow-bf.log
log_type: bitwarden
labels: {}
ignore_parsers: true
override_statics: []

53 changes: 53 additions & 0 deletions .tests/bitwarden-slow-bf/scenario.assert
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
len(results) == 2
"192.168.1.101" in results[0].Overflow.GetSources()
results[0].Overflow.Sources["192.168.1.101"].IP == "192.168.1.101"
results[0].Overflow.Sources["192.168.1.101"].Range == ""
results[0].Overflow.Sources["192.168.1.101"].GetScope() == "Ip"
results[0].Overflow.Sources["192.168.1.101"].GetValue() == "192.168.1.101"
basename(results[0].Overflow.Alert.Events[0].GetMeta("datasource_path")) == "bitwarden-slow-bf.log"
results[0].Overflow.Alert.Events[0].GetMeta("datasource_type") == "file"
results[0].Overflow.Alert.Events[0].GetMeta("log_type") == "bitwarden_failed_auth"
results[0].Overflow.Alert.Events[0].GetMeta("service") == "bitwarden"
results[0].Overflow.Alert.Events[0].GetMeta("source_ip") == "192.168.1.101"
results[0].Overflow.Alert.Events[0].GetMeta("timestamp") == "2023-04-24T10:20:00Z"
basename(results[0].Overflow.Alert.Events[1].GetMeta("datasource_path")) == "bitwarden-slow-bf.log"
results[0].Overflow.Alert.Events[1].GetMeta("datasource_type") == "file"
results[0].Overflow.Alert.Events[1].GetMeta("log_type") == "bitwarden_failed_auth"
results[0].Overflow.Alert.Events[1].GetMeta("service") == "bitwarden"
results[0].Overflow.Alert.Events[1].GetMeta("source_ip") == "192.168.1.101"
results[0].Overflow.Alert.Events[1].GetMeta("timestamp") == "2023-04-24T10:40:00Z"
basename(results[0].Overflow.Alert.Events[2].GetMeta("datasource_path")) == "bitwarden-slow-bf.log"
results[0].Overflow.Alert.Events[2].GetMeta("datasource_type") == "file"
results[0].Overflow.Alert.Events[2].GetMeta("log_type") == "bitwarden_failed_auth"
results[0].Overflow.Alert.Events[2].GetMeta("service") == "bitwarden"
results[0].Overflow.Alert.Events[2].GetMeta("source_ip") == "192.168.1.101"
results[0].Overflow.Alert.Events[2].GetMeta("timestamp") == "2023-04-24T11:00:00Z"
results[0].Overflow.Alert.GetScenario() == "crowdsecurity/bitwarden-slow-bf"
results[0].Overflow.Alert.Remediation == true
results[0].Overflow.Alert.GetEventsCount() == 3
"192.168.1.100" in results[1].Overflow.GetSources()
results[1].Overflow.Sources["192.168.1.100"].IP == "192.168.1.100"
results[1].Overflow.Sources["192.168.1.100"].Range == ""
results[1].Overflow.Sources["192.168.1.100"].GetScope() == "Ip"
results[1].Overflow.Sources["192.168.1.100"].GetValue() == "192.168.1.100"
basename(results[1].Overflow.Alert.Events[0].GetMeta("datasource_path")) == "bitwarden-slow-bf.log"
results[1].Overflow.Alert.Events[0].GetMeta("datasource_type") == "file"
results[1].Overflow.Alert.Events[0].GetMeta("log_type") == "bitwarden_failed_auth"
results[1].Overflow.Alert.Events[0].GetMeta("service") == "bitwarden"
results[1].Overflow.Alert.Events[0].GetMeta("source_ip") == "192.168.1.100"
results[1].Overflow.Alert.Events[0].GetMeta("timestamp") == "2023-04-24T10:00:00Z"
basename(results[1].Overflow.Alert.Events[1].GetMeta("datasource_path")) == "bitwarden-slow-bf.log"
results[1].Overflow.Alert.Events[1].GetMeta("datasource_type") == "file"
results[1].Overflow.Alert.Events[1].GetMeta("log_type") == "bitwarden_failed_auth"
results[1].Overflow.Alert.Events[1].GetMeta("service") == "bitwarden"
results[1].Overflow.Alert.Events[1].GetMeta("source_ip") == "192.168.1.100"
results[1].Overflow.Alert.Events[1].GetMeta("timestamp") == "2023-04-24T10:03:00Z"
basename(results[1].Overflow.Alert.Events[2].GetMeta("datasource_path")) == "bitwarden-slow-bf.log"
results[1].Overflow.Alert.Events[2].GetMeta("datasource_type") == "file"
results[1].Overflow.Alert.Events[2].GetMeta("log_type") == "bitwarden_failed_auth"
results[1].Overflow.Alert.Events[2].GetMeta("service") == "bitwarden"
results[1].Overflow.Alert.Events[2].GetMeta("source_ip") == "192.168.1.100"
results[1].Overflow.Alert.Events[2].GetMeta("timestamp") == "2023-04-24T10:06:00Z"
results[1].Overflow.Alert.GetScenario() == "crowdsecurity/bitwarden-slow-bf"
results[1].Overflow.Alert.Remediation == true
results[1].Overflow.Alert.GetEventsCount() == 3
1 change: 1 addition & 0 deletions collections/MariuszKociubinski/bitwarden.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ parsers:
- MariuszKociubinski/bitwarden-logs
scenarios:
- MariuszKociubinski/bitwarden-bf
- crowdsecurity/bitwarden-slow-bf
description: "Bitwarden Self Hosted support : parser and brute-force detection"
author: MariuszKociubinski
tags:
Expand Down
10 changes: 10 additions & 0 deletions scenarios/crowdsecurity/bitwarden-slow-bf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Detect super slow bitwarden bruteforce attempts that evade traditional rate limiting:

- Uses conditional type with capacity -1 (unlimited)
- Triggers when at least 3 failed authentication attempts occur
- Median interval between attempts exceeds 2 minutes
- Leakspeed of 2h naturally caps maximum interval (~40-60 minutes for 3 events)
- Uses `MedianInterval()` helper to detect consistent timing patterns (more robust against outliers)

This scenario complements the standard bitwarden-bf scenario (capacity 5, leakspeed 20s) by catching attackers who deliberately slow their attempts to avoid detection. The standard scenario catches 5 failures within ~100 seconds, while this catches 3 failures with median interval >2 minutes (naturally capped by 2h leakspeed).

22 changes: 22 additions & 0 deletions scenarios/crowdsecurity/bitwarden-slow-bf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# bitwarden super slow bruteforce detection
type: conditional
name: crowdsecurity/bitwarden-slow-bf
description: "Detect super slow bitwarden bruteforce attempts that evade rate limiting"
filter: "evt.Meta.log_type == 'bitwarden_failed_auth'"
groupby: evt.Meta.source_ip
capacity: -1
condition: |
len(queue.Queue) >= 3 &&
MedianInterval(map(queue.Queue[-3:], { #.Time })) > duration("2m")
leakspeed: 2h
blackhole: 5m
labels:
service: bitwarden
behavior: "http:bruteforce"
spoofable: 0
confidence: 3
classification:
- attack.T1110
label: "Bitwarden Slow Bruteforce"
remediation: true

Loading