huan/docker-simple-mail-forwarder

SASL login brutforce mitigation

saikek opened this issue ยท 9 comments

Hello,

on my private hosting, i'm getting lots of hits on mail port with SASL authentication attempts.
Could you please mention to the main page fail2ban SASL mitigation? Otherwise we would end up with lots of mail-bots. (If this issue is valid with your server).

For example:
https://bobcares.com/blog/fail2ban-postfix-sasl/

It took me some time to make it work. Main issue - with correct regex - due to wrong timezone, date wasn't properly matched, so bans were not applied. Here are my solution:

/etc/fail2ban/jail.d/saslmail.conf

[DEFAULT]
sender = root@localhost
destemail = root@localhost
action = %(action_mwl)s

[saslmail]
enabled  = true
port     = 25
protocol = udp
filter   = saslmail
logpath  = /var/lib/docker/containers/<container>/<container>-json.log
maxretry = 2
bantime = 3600
[INCLUDES]
before = common.conf

`/etc/fail2ban/filter.d/saslmail.conf`
[Definition]
failregex = ^.*\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed.*$
            ^.*reject: RCPT from \S+\[<HOST>\]:.*Relay access denied.*$
            ^.*lost connection after .*\[<HOST>\].*$

datepattern =%%b %%d %%H:%%M:%%S

Please update README with security issues.

huan commented

@saikek Thanks for filing this issue.

Could you please help us to submit a PR to update the README for the project? Because I'm not very familiar with this problem.

Thank you very much.

@saikek Thank you very much for your ground work.

I now have this:

/ # fail2ban-client status saslmail
Status for the jail: saslmail
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /logs/simple_mail_forward.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:
/ # fail2ban-regex /logs/simple_mail_forward.log /data/filter.d/saslmail.conf

Running tests
=============

Use   failregex filter file : saslmail, basedir: /data
Use      datepattern : MON Day 24hour:Minute:Second
Use         log file : /logs/simple_mail_forward.log
Use         encoding : UTF-8


Results
=======

Failregex: 12314 total
|-  #) [# of hits] regular expression
|   1) [8110] ^.*\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed.*$
|   2) [2] ^.*reject: RCPT from \S+\[<HOST>\]:.*Relay access denied.*$
|   3) [4202] ^.*lost connection after .*\[<HOST>\].*$
`-

Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [33252] MON Day 24hour:Minute:Second
`-

Lines: 33636 lines, 0 ignored, 12314 matched, 21322 missed
[processed in 2.59 sec]

The filter is working, but somehow no bans are applied whatsoever when running the container. Any clues?

shafr commented

Many reasons why:

  • Docker container timezone and time does not correspond to a system timezone. It can have UTC timezone and host machine can have anything else.
  • Docker uses it's own IPTABLE rules. So fail2ban IPTABLE rules does not apply easily with docker. fail2ban solution
  • Docker requests are coming from ip 172.17.0.1 - which is not internet IP but rather Docker Gateway. (Which is caused by IP masquerading)
shafr commented

I've ended up stopping service until I would have time to fix it. Better safe then sorry.

It's working for me now!

I've used a docker container with fail2ban ( https://github.com/crazy-max/docker-fail2ban )
compose file:

  fail2ban:
    image: crazymax/fail2ban:latest
    container_name: fail2ban
    network_mode: "host"
    cap_add:
      - NET_ADMIN
      - NET_RAW
    volumes:
      - "${DOCKERDIR}/fail2ban/data:/data"
      - "/var/log:/var/log:ro"
      - "/var/lib/docker/containers/bf114b2df522e48cb486ad1db7cc1dae351c7c8539d64a5e111d6ef4cbfbabfd/bf114b2df522e48cb486ad1db7cc1dae351c7c8539d64a5e111d6ef4cbfbabfd-json.log:/logs/sim$
    env_file:
      - "${DOCKERDIR}/fail2ban/fail2ban.env"
    restart: always

Notice the horrible path of the docker container for simple-mail-forwarder because there is no postfix log. This path is different for every installation. You can easily find the path by running

docker inspect --format="{{.Id}}" "simple-mail-forward" | xargs find /var/lib/docker/containers -name

Where "simple-mail-forward" is the name of your SMF docker container.

saslmail.conf (filter.d)

[Definition]
failregex = ^.*\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed.*$
            ^.*reject: RCPT from \S+\[<HOST>\]:.*Relay access denied.*$
            ^.*lost connection after .*\[<HOST>\].*$

saslmail.conf (jail.d)

[saslmail]
enabled  = true
findtime = 14400
bantime  = 93600
port     = 25
filter   = saslmail
logpath  = /logs/simple_mail_forward.log

Because the timezone is incorrect in the SMF container I have to account for 2 extra hours for findtime & bantime. This might differ according to your timezone.

Result:

fail2ban-client status saslmail
Status for the jail: saslmail
|- Filter
|  |- Currently failed: 2
|  |- Total failed:     4
|  `- File list:        /logs/simple_mail_forward.log
`- Actions
   |- Currently banned: 5
   |- Total banned:     5
   `- Banned IP list:   45.13.39.140 185.137.111.129 185.137.111.136 185.137.111.96 185.137.111.125

Send to mail log files are finally silent after continuous hammering.

shafr commented

@me1299 - try this line in your jail.d file:

[saslmail]
...
logtimezone = UTC
...

This should would work without docker-compose file.

Also you can use path for logs:

/var/lib/docker/containers/*/*-json.log

I don't think it would create big overhead even if you are running multiple containers.

Also Also:
Are you sure that all requests are now blocked - I had occasions with "IP already blocked" - which was actually not locking anything

@me1299 - try this line in your jail.d file:

[saslmail]
...
logtimezone = UTC
...

This should would work without docker-compose file.

Also you can use path for logs:

/var/lib/docker/containers/*/*-json.log

I don't think it would create big overhead even if you are running multiple containers.

Also Also:
Are you sure that all requests are now blocked - I had occasions with "IP already blocked" - which was actually not locking anything

Timezone is now fixed in the latest release, so that isn't an issue anymore. I like your idea of mapping all log files, but I'm not a fan of the overhead it creates.

And yes, I'm 100% sure the requests are blocked. My iptables on the host:

-A f2b-saslmail -s 45.13.39.140/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 37.49.224.140/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 185.234.219.66/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 185.234.219.62/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 185.234.219.61/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 185.234.218.126/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 185.234.216.206/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 185.137.111.96/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 185.137.111.136/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 185.137.111.129/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 185.137.111.125/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 103.231.139.5/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-saslmail -s 103.231.139.3/32 -j REJECT --reject-with icmp-port-unreachable