Slow, distributed password guessing against the mail server stays under CrowdSec's radar – idea for a "slow" scenario

Hi all,

while reviewing my mail logs (NS8, mail + crowdsec on the same node) I found about 170,000 failed SMTP AUTH attempts in seven weeks that CrowdSec never reacted to. Nothing got in, but I think the pattern is worth sharing, because it looks deliberately built to stay below the default thresholds.

What I see

  • ~156,000 of the failures came from a single /22 (37 addresses of one /24 were active), continuously from the end of July to mid September.
  • Each address tries one login every ~10 minutes, 24 hours a day, with a different user name each time (info, admin, sales, first names…). Per address that is only ~6 attempts per hour – all together still ~220 per hour.
  • The same would work with addresses from completely different networks (botnet); in my case they happened to sit in one /24.

Why CrowdSec stays silent

SMTP AUTH is checked by dovecot, so the only scenario that sees these failures is crowdsecurity/dovecot-spam: capacity 3, leakspeed 360s, grouped by source IP. One attempt every 10 minutes leaks away faster (one per 6 minutes) than it fills the bucket – it can never overflow, no matter how many weeks it runs. The postfix scenarios do not look at SASL LOGIN authentication failed at all. For SSH the hub has ssh-slow-bf for exactly this case; for mail there is nothing comparable.

Idea: a slow scenario for mail, per IP and per /24

I tested these two on a replay of synthetic logs (CrowdSec 1.7.8, -dsn file://… -no-api) and they now run on my node as local scenarios:

type: leaky
name: local/dovecot-slow-bf
description: "Detect slow dovecot/SASL password guessing from one IP"
filter: "evt.Meta.log_type == 'dovecot_logs' && evt.Meta.dovecot_login_result == 'auth_failed'"
groupby: evt.Meta.source_ip
capacity: 10
leakspeed: 30m
blackhole: 1h
labels:
  service: mail
  type: bruteforce
  remediation: true
type: leaky
name: local/dovecot-slow-bf-range
description: "Detect distributed slow dovecot/SASL password guessing from one /24"
filter: "evt.Meta.log_type == 'dovecot_logs' && evt.Meta.dovecot_login_result == 'auth_failed'"
groupby: IpToRange(evt.Meta.source_ip, "/24")
distinct: evt.Meta.source_ip + evt.Meta.dovecot_user
capacity: 30
leakspeed: 5m
blackhole: 1h
scope:
  type: Range
  expression: IpToRange(evt.Meta.source_ip, "/24")
labels:
  service: mail
  type: bruteforce
  remediation: true

Replay results: one address trying every 10 minutes is caught after 2 h 20 min (15 events); 37 addresses of one /24 at the same pace are caught as a range after 8 minutes; a real user who mistypes a password twice, three times a day, never triggers either of them. I keep the range scenario in simulation mode for now, because a /24 ban can hit a provider.

Files go to state/crowdsec_config/scenarios/ of the crowdsec instance (bind-mounted to /etc/crowdsec), then restart the crowdsec service; cscli simulation enable <name> for a dry run.

Two related observations about the ban time

  1. With dynamic ban time enabled, the value from the UI is in minutes and grows linearly: (number of earlier bans + 1) * 4 minutes with the default of 4. A first offender is back after 4–8 minutes; my most persistent address needed 57 bans to reach about 4 hours. Would a doubling per repeat (4 min, 8, 16, … with a cap) be an option for the module? profiles.yaml.local is regenerated at every service start, so this cannot be changed locally in a durable way.
  2. For one address that is also on the community blocklist, CrowdSec logged a local ban (216m ban on Ip …) several times, but the attempts continued every 4 minutes through the ban windows, and the firewall bouncer logged no “decision added” at those moments. After a restart of the node the address was blocked. I have not found the cause yet – has anyone seen local decisions not reaching the bouncer when a CAPI decision for the same IP exists?

Does this match what others see in their logs? If the slow scenarios look reasonable, maybe they – or something better – could ship with the crowdsec module for nodes that run mail.

Thanks!

I’ve seen related behavior.

please install melite scenario

 melite/dovecot-slow-bf                            ✔️  enabled         0.1      /etc/crowdsec/scenarios/dovecot-slow-bf.yaml                    
 melite/dovecot-time-based-bf                      ✔️  enabled         0.1      /etc/crowdsec/scenarios/dovecot-time-based-bf.yaml