Skip to content
Merged
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
20 changes: 18 additions & 2 deletions .tests/ssh-time-based-bf/scenario.assert
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,17 @@ results[0].Overflow.Alert.Events[2].GetMeta("service") == "ssh"
results[0].Overflow.Alert.Events[2].GetMeta("source_ip") == "10.0.0.101"
results[0].Overflow.Alert.Events[2].GetMeta("target_user") == "oracle"
results[0].Overflow.Alert.Events[2].GetMeta("timestamp") == "2026-09-30T11:40:00Z"
basename(results[0].Overflow.Alert.Events[3].GetMeta("datasource_path")) == "ssh-time-based-bf.log"
results[0].Overflow.Alert.Events[3].GetMeta("datasource_type") == "file"
results[0].Overflow.Alert.Events[3].GetMeta("log_type") == "ssh_failed-auth"
results[0].Overflow.Alert.Events[3].GetMeta("machine") == "server"
results[0].Overflow.Alert.Events[3].GetMeta("service") == "ssh"
results[0].Overflow.Alert.Events[3].GetMeta("source_ip") == "10.0.0.101"
results[0].Overflow.Alert.Events[3].GetMeta("target_user") == "postgres"
results[0].Overflow.Alert.Events[3].GetMeta("timestamp") == "2026-09-30T12:00:00Z"
results[0].Overflow.Alert.GetScenario() == "crowdsecurity/ssh-time-based-bf_user-enum"
results[0].Overflow.Alert.Remediation == false
results[0].Overflow.Alert.GetEventsCount() == 3
results[0].Overflow.Alert.GetEventsCount() == 4
"10.0.0.101" in results[1].Overflow.GetSources()
results[1].Overflow.Sources["10.0.0.101"].IP == "10.0.0.101"
results[1].Overflow.Sources["10.0.0.101"].Range == ""
Expand Down Expand Up @@ -60,6 +68,14 @@ results[1].Overflow.Alert.Events[2].GetMeta("service") == "ssh"
results[1].Overflow.Alert.Events[2].GetMeta("source_ip") == "10.0.0.101"
results[1].Overflow.Alert.Events[2].GetMeta("target_user") == "oracle"
results[1].Overflow.Alert.Events[2].GetMeta("timestamp") == "2026-09-30T11:40:00Z"
basename(results[1].Overflow.Alert.Events[3].GetMeta("datasource_path")) == "ssh-time-based-bf.log"
results[1].Overflow.Alert.Events[3].GetMeta("datasource_type") == "file"
results[1].Overflow.Alert.Events[3].GetMeta("log_type") == "ssh_failed-auth"
results[1].Overflow.Alert.Events[3].GetMeta("machine") == "server"
results[1].Overflow.Alert.Events[3].GetMeta("service") == "ssh"
results[1].Overflow.Alert.Events[3].GetMeta("source_ip") == "10.0.0.101"
results[1].Overflow.Alert.Events[3].GetMeta("target_user") == "postgres"
results[1].Overflow.Alert.Events[3].GetMeta("timestamp") == "2026-09-30T12:00:00Z"
results[1].Overflow.Alert.GetScenario() == "crowdsecurity/ssh-time-based-bf"
results[1].Overflow.Alert.Remediation == false
results[1].Overflow.Alert.GetEventsCount() == 3
results[1].Overflow.Alert.GetEventsCount() == 4
13 changes: 9 additions & 4 deletions .tests/ssh-time-based-bf/ssh-time-based-bf.log
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ Sep 30 10:12:00 server sshd[12347]: Invalid user guest from 10.0.0.100 port 5676
Sep 30 11:00:00 server sshd[12348]: Invalid user root from 10.0.0.101 port 56765
Sep 30 11:20:00 server sshd[12349]: Invalid user mysql from 10.0.0.101 port 56766
Sep 30 11:40:00 server sshd[12350]: Invalid user oracle from 10.0.0.101 port 56767
Sep 30 12:00:00 server sshd[12351]: Invalid user postgres from 10.0.0.102 port 56768
Sep 30 12:10:00 server sshd[12352]: Invalid user jenkins from 10.0.0.102 port 56769
Sep 30 12:15:00 server sshd[12353]: Accepted password for jenkins from 10.0.0.102 port 56770 ssh2
Sep 30 12:20:00 server sshd[12354]: Invalid user admin from 10.0.0.102 port 56771
Sep 30 12:00:00 server sshd[12351]: Invalid user postgres from 10.0.0.101 port 56768
Sep 30 12:30:00 server sshd[12352]: Invalid user admin from 10.0.0.102 port 56769
Sep 30 12:40:00 server sshd[12353]: Invalid user test from 10.0.0.102 port 56770
Sep 30 12:45:00 server sshd[12354]: Accepted password for test from 10.0.0.102 port 56771 ssh2
Sep 30 12:50:00 server sshd[12355]: Invalid user guest from 10.0.0.102 port 56772
Sep 30 13:00:00 server sshd[12356]: Invalid user root from 10.0.0.103 port 56773
Sep 30 13:00:02 server sshd[12357]: Invalid user admin from 10.0.0.103 port 56774
Sep 30 13:00:04 server sshd[12358]: Invalid user test from 10.0.0.103 port 56775
Sep 30 14:00:04 server sshd[12359]: Invalid user guest from 10.0.0.103 port 56776
8 changes: 4 additions & 4 deletions scenarios/crowdsecurity/ssh-time-based-bf.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Detect time-based ssh bruteforce attempts that evade traditional rate limiting with false positive reduction:

- Uses conditional type with capacity -1 (unlimited)
- Triggers when at least 3 failed authentication attempts occur
- Triggers when at least 4 failed authentication attempts occur
- Median interval between failed attempts exceeds 10 minutes
- **False positive reduction**: Uses `cancel_on` to cancel bucket if user successfully authenticates
- Prevents "forgot password" scenarios from triggering alerts
Expand All @@ -14,10 +14,10 @@ Detect time-based ssh bruteforce attempts that evade traditional rate limiting w
- Requires `crowdsecurity/sshd-success-logs` parser for cancel_on functionality

**Two variants:**
1. **ssh-time-based-bf**: Standard bruteforce detection (3 failed logins from same IP)
2. **ssh-time-based-bf_user-enum**: User enumeration detection (3 distinct usernames from same IP)
1. **ssh-time-based-bf**: Standard bruteforce detection (4 failed logins from same IP)
2. **ssh-time-based-bf_user-enum**: User enumeration detection (4 distinct usernames from same IP)

This scenario complements the standard ssh-bf (capacity 5, leakspeed 10s) and ssh-slow-bf (capacity 10, leakspeed 60s) scenarios with no overlap:
- ssh-bf catches 5 failures within ~50 seconds (rate-based)
- ssh-slow-bf catches 10 failures within ~10 minutes (rate-based)
- ssh-time-based-bf catches 3 failures with median interval >10 minutes (time-pattern-based, naturally capped by 2h leakspeed)
- ssh-time-based-bf catches 4 failures with median interval >10 minutes (time-pattern-based, naturally capped by 2h leakspeed)
8 changes: 4 additions & 4 deletions scenarios/crowdsecurity/ssh-time-based-bf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ capacity: -1
cancel_on: "evt.Meta.log_type == 'auth_success'"
condition: |
let failedAuths = filter(queue.Queue, {#.Meta.log_type == 'ssh_failed-auth'});
len(failedAuths) >= 3 &&
MedianInterval(map(failedAuths[-3:], {#.Time})) > duration("10m")
len(failedAuths) >= 4 &&
MedianInterval(map(failedAuths[-4:], {#.Time})) > duration("10m")
leakspeed: 2h
blackhole: 5m
reprocess: true
Expand All @@ -34,8 +34,8 @@ capacity: -1
cancel_on: "evt.Meta.log_type == 'auth_success'"
condition: |
let failedAuths = filter(queue.Queue, {#.Meta.log_type == 'ssh_failed-auth'});
len(failedAuths) >= 3 &&
MedianInterval(map(failedAuths[-3:], {#.Time})) > duration("10m")
len(failedAuths) >= 4 &&
MedianInterval(map(failedAuths[-4:], {#.Time})) > duration("10m")
leakspeed: 2h
blackhole: 5m
reprocess: true
Expand Down