[exim] Re: smtp_accept_max & DDoS

Top Page
Delete this message
Reply to this message
Author: Lena--- via Exim-users
Date:  
To: exim-users
Subject: [exim] Re: smtp_accept_max & DDoS
> To: exim-users @ lists.exim.org

~ $ dig lists.exim.org mx
;; QUESTION SECTION:
;lists.exim.org.                        IN      MX


;; ANSWER SECTION:
lists.exim.org.         294     IN      CNAME   cumin.exim.org.
cumin.exim.org.         300     IN      MX      10 cumin.exim.org.


In my home computer (with FreeBSD) by default the MSA is sendmail, I suppose
it "canonicalizes" the hostname before submission to my MTA on my VPS (Exim).

2023-05-12 00:24:49 +0300
H=cumin.exim.org [37.120.190.30]
SMTP error from remote mail server after RCPT TO:<exim-users @ cumin.exim.org>: 550 unknown user

In my home computer I had to add to /usr/local/etc/unbound/unbound.conf :

local-data: "lists.exim.org MX 10 cumin.exim.org"

> From: Slavko <linux@???>


> The problem is in exim. It gets (logs) "authenticator failed ..." line,
> that line contains "535 Incorrect authentication data ..." too. Then
> it responds that (i guess) to client, which never responds. The
> connection is then hold open, until timeout happens (in my case
> i lowered it to 60 sec). As attackers does that login attempts in
> waves 10-15 IPs in short time, here are multiple connections
> openned until timeout happens.


How do you know that connection is held open and timeout happens?
I seldom see that in my logs.
During last 30 days I see (logged in notquit ACL)
3867 connection-lost and 63 command-timeout events
after authentication failed.
In my config:

smtp_max_synprot_errors = 0
WARNTO = Lena@???
SHELL = /bin/sh
ADDRNAME = $sender_host_address $acl_c_country ${sg{${lookup dnsdb{>, defer_never,ptr=$sender_host_address}}}{\N[^\w.,-]\N}{}}
chunking_advertise_hosts =
slow_lookup_log = 1500
auth_advertise_hosts = ${if eq{$sender_helo_name}{ylmf-pc}{}{*}}
log_timezone
smtp_accept_max = 15
smtp_accept_max_nonmail = 9
log_selector = +smtp_confirmation +queue_time +queue_time_overall \
           +deliver_time +receive_time -retry_defer \
           +smtp_incomplete_transaction +smtp_no_mail +incoming_interface
acl_smtp_connect = acl_check_connect
acl_smtp_helo = acl_check_helo
acl_smtp_auth = acl_check_auth
acl_smtp_mail = acl_check_mail
acl_smtp_quit = acl_check_quit
acl_smtp_notquit = acl_check_notquit
host_lookup = *
rfc1413_hosts = *
rfc1413_query_timeout = 2s
HELODETAINTED = ${sg{$sender_helo_name}{\N[^\w.,-]\N}{}}
# these two masks are used only in case of IPv6:
# how many IPv6 addresses you give to your single user:
MASKL = ${if match{$sender_host_address}{:}{/64}}
# how many external IPv6 addresses you treat as one attacker:
MASKW = ${if match{$sender_host_address}{:}{/56}}
...
begin acl
...
acl_check_connect:
  drop    message = $sender_host_address locally blacklisted for a bruteforce \
          auth (login+password) cracking attempt
    condition = ${if exists{$spool_directory/blocked_IPs}}
    condition = ${lookup{$sender_host_address}iplsearch\
                    {/var/..$spool_directory/blocked_IPs}{1}{0}}
  drop    message = stretchoid and similar scanners banned
        condition = ${if match\
        {${lookup dnsdb{defer_never,ptr=$sender_host_address}}}\
        {\N\.(stretchoid.com|shodan.io|internet-research-project.net|binaryedge.ninja|tchelebi.io|alphastrike.io|airtelbroadband.in|proxy-research.com)$\N}}


accept

acl_check_helo:
...
  drop    message = suspicious client with helo=$sender_helo_name \
          locally blacklisted
    condition = ${if eq{$sender_helo_name}{ylmf-pc}}
        acl = setdnslisttext
    condition = ${if match{$acl_c_country}{(?i)br|cn|vn}}
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs'}}


  drop    message = suspicious client with helo=$sender_helo_name \
          locally blacklisted
    condition = ${if match{$sender_helo_name}\
              {\N^(ganymede|ylmf-pc|\*\.\*|\[192\.168\.2\.33\])$\N}}
        acl = setdnslisttext
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs; \
       \N{\N echo Subject: HELODETAINTED. blocked ADDRNAME; \
           echo; echo for bruteforce auth cracking attempt.; \
       \N}\N | $exim_path -f root WARNTO'}}


accept

acl_check_auth:
  drop    message = authentication is allowed only once per message in order \
          to slow down bruteforce cracking
    set acl_m_auth = ${eval10:0$acl_m_auth+1}
    condition = ${if >{$acl_m_auth}{2}}
    delay = 22s


  drop    message = blacklisted for bruteforce cracking attempt
    set acl_c_authnomail = ${eval10:0$acl_c_authnomail+1}
    condition = ${if >{$acl_c_authnomail}{4}}
    condition = ${if exists{$spool_directory/blocked_IPs}\
             {${lookup{$sender_host_address}iplsearch\
                           {$spool_directory/blocked_IPs}{0}{1}}}\
                         {1}}
        acl = setdnslisttext
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs; \
       \N{\N echo Subject: blocked ADDRNAME; echo; echo \
       for bruteforce auth cracking attempt.; \
       \N}\N | $exim_path -f root WARNTO'}}


  drop  message = blacklisted for bruteforce cracking attempt
        condition = ${if >{$acl_c_authnomail}{4}}


  accept set acl_c_authhash = ${if match{$smtp_command_argument}\
          {\N(?i)^(?:plain|login) (.+)$\N}{${nhash_1000:$1}}}


acl_check_mail:
  deny    message = 503 Bad sequence of commands - must send HELO/EHLO first
    condition = ${if !def:sender_helo_name}


accept set acl_c_authnomail = 0

setdnslisttext:
  accept dnslists = all.ascc.dnsbl.bit.nl
     set acl_c_country = ${if match{$dnslist_text}{ CC=(\\S+) }{$1}}


accept

acl_check_quit:
  accept condition = $authentication_failed
    logwrite = :reject: quit after authentication failed: \
                ${sg{$sender_rcvhost}{\N[\n\t]+\N}{\040}}
        acl = setdnslisttext
    condition = ${if match{$acl_c_country}{(?i)br|cn|vn}}
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs'}}


  warn    condition = $authentication_failed
        dnslists = auth.spamrats.com
        # http://spamrats.com/rats-auth.php , http://spamrats.com/about.php
    condition = ${if exists{$spool_directory/blocked_IPs}\
             {${lookup{$sender_host_address}iplsearch\
                           {$spool_directory/blocked_IPs}{0}{1}}}\
                         {1}}
        acl = setdnslisttext
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs; \
       \N{\N echo Subject: spamrats. blocked ADDRNAME; \
       echo; echo for auth cracking attempt.; \
       \N}\N | $exim_path -f root WARNTO'}}


  warn    condition = $authentication_failed
        condition = ${if match{$sender_helo_name}\
            {\N^(User|xray500|FlapJack|gerg|smtp.lena.kiev.ua)$\N}}
    condition = ${if exists{$spool_directory/blocked_IPs}\
             {${lookup{$sender_host_address}iplsearch\
                           {$spool_directory/blocked_IPs}{0}{1}}}\
                         {1}}
        acl = setdnslisttext
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs; \
       \N{\N echo Subject: HELODETAINTED. blocked ADDRNAME; \
       echo; echo for auth cracking attempt.; \
       \N}\N | $exim_path -f root WARNTO'}}


  warn  condition = $authentication_failed
        condition = ${if def:acl_c_authhash}
        ratelimit = 0 / 5m / strict / $sender_host_address-$acl_c_authhash
        set acl_c_hashrate = ${sg{$sender_rate}{[.].*}{}}


  warn    condition = $authentication_failed
        condition = ${if or{\
                            {!def:acl_c_authhash}\
                            {<{$acl_c_hashrate}{2}}\
                           }}
    ratelimit = 7 / 5m / strict / per_conn
    condition = ${if exists{$spool_directory/blocked_IPs}\
             {${lookup{$sender_host_address}iplsearch\
                           {$spool_directory/blocked_IPs}{0}{1}}}\
                         {1}}
        acl = setdnslisttext
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs; \
       \N{\N echo Subject: blocked ADDRNAME; echo; echo \
       for bruteforce auth cracking attempt.; \
       \N}\N | $exim_path -f root WARNTO'}}


acl_check_notquit:
  accept condition = $authentication_failed
    logwrite = :reject: $smtp_notquit_reason after authentication failed: \
                ${sg{$sender_rcvhost}{\N[\n\t]+\N}{\040}}
        acl = setdnslisttext
    condition = ${if match{$acl_c_country}{(?i)br|cn|vn}}
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs'}}


  warn    condition = $authentication_failed
        dnslists = auth.spamrats.com
        # http://spamrats.com/rats-auth.php , http://spamrats.com/about.php
    condition = ${if exists{$spool_directory/blocked_IPs}\
             {${lookup{$sender_host_address}iplsearch\
                           {$spool_directory/blocked_IPs}{0}{1}}}\
                         {1}}
        acl = setdnslisttext
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs; \
       \N{\N echo Subject: spamrats. blocked ADDRNAME; \
       echo; echo for auth cracking attempt.; \
       \N}\N | $exim_path -f root WARNTO'}}


  warn    condition = $authentication_failed
    condition = ${if match{$smtp_notquit_reason}\
                  {^(connection-lost|synchronization-error)}}
        condition = ${if match{$sender_helo_name}\
        {\N^(User|xray500|FlapJack|gerg|SERVER-KP1|((mail|smtp)\.)?(lena\.kiev|(ksana|sergej)\.org)\.ua)$\N}}
    !hosts = @[]
    condition = ${if exists{$spool_directory/blocked_IPs}\
             {${lookup{$sender_host_address}iplsearch\
                           {$spool_directory/blocked_IPs}{0}{1}}}\
                         {1}}
        acl = setdnslisttext
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs; \
       \N{\N echo Subject: HELODETAINTED. blocked ADDRNAME; \
       echo; echo for auth cracking attempt.; \
       \N}\N | $exim_path -f root WARNTO'}}


  warn  condition = $authentication_failed
        condition = ${if def:acl_c_authhash}
        ratelimit = 0 / 2h / strict / $sender_host_address-$acl_c_authhash
        set acl_c_hashrate = ${sg{$sender_rate}{[.].*}{}}


  warn    condition = $authentication_failed
        condition = ${if match{$smtp_notquit_reason}\
                              {^(connection-lost|synchronization-error)}}
        condition = ${if or{\
                            {!def:acl_c_authhash}\
                            {<{$acl_c_hashrate}{2}}\
                           }}
    ratelimit = 7 / 2h / strict / per_conn
    condition = ${if exists{$spool_directory/blocked_IPs}\
             {${lookup{$sender_host_address}iplsearch\
                           {$spool_directory/blocked_IPs}{0}{1}}}\
                         {1}}
        acl = setdnslisttext
    continue = ${run{SHELL -c 'echo \\\"$sender_host_addressMASKW\\\" \
       >>$spool_directory/blocked_IPs; \
       \N{\N echo Subject: blocked ADDRNAME; echo; echo \
       for bruteforce auth cracking attempt.; \
       \N}\N | $exim_path -f root WARNTO'}}


hash:
accept set acl_c_authhash = ${nhash_1000:$acl_arg1}

...
begin authenticators

plain:
driver = plaintext
public_name = PLAIN
server_prompts = :
server_condition = ${if pam{$auth2:${sg{$auth3}{:}{::}}}}${acl{hash}{$auth2,$auth3}}
client_send = ^${extract{user}{$address_data}{$value}fail}^${extract{pass}{$address_data}{$value}fail}
server_set_id = $2

login:
driver = plaintext
public_name = LOGIN
server_prompts = "Username:: : Password::"
server_condition = ${if pam{$auth1:${sg{$auth2}{:}{::}}}}${acl{hash}{$auth1,$auth2}}
server_set_id = $1


--
## subscription configuration (requires account):
## https://lists.exim.org/mailman3/postorius/lists/exim-users.lists.exim.org/
## unsubscribe (doesn't require an account):
## exim-users-unsubscribe@???
## Exim details at http://www.exim.org/
## Please use the Wiki with this list - http://wiki.exim.org/