By Weldon Whipple <firstname.lastname@example.org>
The recent flood of spam, viruses and trojaned Windows machines has brought a dramatic increase in attacks on e-mail servers, including (but not limited to) denial-of-service (DoS) attacks, distributed denial-of-service (DDoS) attacks, Joe Jobs, dictionary attacks, slamming, and other assorted nuisances. This document describes some sendmail facilities--many of them new in version 8.13--that can help foil these attacks.
Version 8.13.0 of Sendmail introduced the ratecontrol feature, which uses the access database to limit the number of incoming connections a single server, group of servers or all unspecified ("wildcard") servers can make to your server per minute. When an incoming server exceeds those limits, sendmail returns a temporary failure, causing the (standards compliant) incoming server to queue the mail and retry delivery later.
The "per minute" connection rate window is configurable. If, as you configure the ratecontrol feature, you decide that you want to change the connection rate window, add the following to your sendmail macro configuration (mc) file:define(`confCONNECTION_RATE_WINDOW_SIZE',`secs')dnlwhere secs is an integer that specifies the number of seconds you want in the window.
The ratecontrol feature declaration must follow the access db declaration (somewhere) in your sendmail mc file:
FEATURE(`access_db')dnl FEATURE(`ratecontrol', ,`terminate')dnl
If your existing configuration uses the delay_checks feature to whitelist recipients (for example), you must tell the ratecontrol feature not to delay those checks, by specifying "nodelay" as the second argument to the ratecontrol feature:FEATURE(`access_db')dnl FEATURE(`delay_checks',`friend')dnl FEATURE(`ratecontrol', `nodelay',`terminate')dnlThe delay_checks feature is outside the scope of this document. See the cf/README file (in the sendmail distribution) or section 7.5.6 of the Bat Book.
The third argument ("terminate", above) causes sendmail to immediately terminate an excessive incoming connection with a 421 status code. If you omit the third argument (declaring the feature something like FEATURE(`ratecontrol'), for example), sendmail will issue a 452 status, which leaves it up to the incoming mail server to issue an SMTP QUIT. If you omit "terminate", an unfriendly incoming server can continue to issue (failing) SMTP commands--probably not what you want to have happen.
After modifying your mc file, generate and install a new sendmail.cf file and restart sendmail.
The method of generating a sendmail.cf varies from platform to platform. This link describes how to do it on FreeBSD. To restart sendmail on FreeBSD, enter the commands:# cd /etc/mail # make restart
After modifying sendmail.cf and restarting sendmail, edit /etc/mail/access (or wherever your distribution stores the source for the access database) and add entries something like the following:
ClientRate:192.168.2.3 2 ClientRate:127.0.0.1 0 ClientRate: 10 ClientRate:10.3.4 2The above limits incoming server 192.168.2.3 to two connections per minute, localhost is unlimited, each individual host in the subnet 10.3.4 can have at most 2 connections per minute, and any other host can have up to 10 connections per minute
Note about mail clients that relay mail through the server. Remote e-mail clients that (legitimately, using SMTP AUTH, for example) relay mail through the server are subject to the ClientRate settings in access db. In the above example, if the "wildcard" is changed from 10 to 1, and a client not matched by other ClientRate: entries attempts to send more than one e-mail in a minute's time, all but the first e-mail will fail. ... So be aware of your clients that use your server as their outgoing SMTP server as you configure ratecontrol in the access database.
After editing the access source file, regenerate access db with something like:
# cd /etc/mail # makemap hash access < access
On FreeBSD, you can generate access.db with the simpler# cd /etc/mail # make
There are times when the ratecontrol feature might not give adequate protection. In a distributed denial-of-service (DDoS) attack, for example, an "army" of attacking servers individually limited to as few as 1 connection per minute might collectively overwhelm sendmail. The ConnectionRateThrottle causes sendmail to accept no more than a specified number of new connections per second.
If (for example) you set the ConnectionRateThrottle at 3, and 9 incoming connections arrive simultaneously, sendmail will handle the first three during the first second, the second three during the second second, and the third three during the third second. Connections that exceed the specified ConnectionRateThrottle are forced to wait their turn.
To set the ConnectionRateThrottle, insert the following in your sendmail mc file:
define(`confCONNECTION_RATE_THROTTLE', `num')dnlwhere num is a positive integer.
If you specify a value or 0 or a negative integer--or omit the line completely--then sendmail will not enforce a connection rate throttle.
Limiting the rate of incoming connections alone might not protect your server from a DoS attack. In order to ensure that the "mail will go through," sendmail's default timeout values for each phase of a mail transaction are very generous (in keeping with values recommended by Internet standards documents). As a result, it is conceivable (in fact not uncommon) for a single envelope delivery to take well over an hour. Unless prevented from doing so, malevolent attackers can slowly accumulate connections to your server, causing it to exhaust its resources.
Fortunately, sendmail 8.13 introduced the conncontrol feature to limit the number of simultaneous connections a single server can maintain with your server.
If you've read and understood the ratecontrol feature (above), conncontrol will seem familiar. Begin by editing your sendmail mc file. The conncontrol feature declaration must com after the access db declaration in the mc file:
FEATURE(`access_db')dnl FEATURE(`conncontrol', ,`terminate')dnl
If your existing configuration uses the delay_checks feature to whitelist recipients (for example), you must tell the conncontrol feature not to delay those checks, by specifying "nodelay" as the second argument to the conncontrol feature:FEATURE(`access_db')dnl FEATURE(`delay_checks',`friend')dnl FEATURE(`conncontrol', `nodelay',`terminate')dnlThe delay_checks feature is outside the scope of this document. See the cf/README file (in the sendmail distribution) or section 7.5.6 of the Bat Book. As with ratecontrol, conncontrol's third ("terminate") argument causes sendmail to immediately terminate an excessive incoming connection with a 421 status code. If you omit the third argument (declaring the feature something like FEATURE(`conncontrol'), for example), sendmail will issue a 452 status, which leaves it up to the incoming mail server to issue an SMTP QUIT and break the connection(!). If you omit "terminate", an unfriendly incoming server can continue to issue (failing) SMTP commands--holding the connection open!! (definitely not what you want to happen).
After modifying sendmail.cf and restarting sendmail, add ClientConn: entries to the access db. For example:
ClientConn:192.168.2.3 2 ClientConn:127.0.0.1 0 ClientConn: 10 ClientConn:10.3.4 2will limit incoming server 192.168.2.3 to a maximum of two simultaneous connections, allow localhost to have unlimited connections, limit each host in the subnet 10.3.4 to two simultaneous connections, and any other individual host can have up to 10 simultaneous connections.
After adding ClientConn-tagged entries to access source file, regenerate access.db.
In a typical dictionary attack, the attacking server sends a single message to a list of well-known or "promising" e-mail addresses at the target domain. After exchanging greetings and issuing the MAIL FROM: command to identify the (probably spurious) sender, the attacker issues a series of RCPT TO: commands, something like:
RCPT TO:<email@example.com> RCPT TO:<firstname.lastname@example.org> RCPT TO:<email@example.com> RCPT TO:<firstname.lastname@example.org> RCPT TO:<email@example.com> RCPT TO:<firstname.lastname@example.org> [more recipients ...] RCPT TO:<email@example.com>After identifying the recipients, the attacker continues the transmission by issuing the DATA command and sending the message headers and body.
Because of the guessing involved, dictionary attacks have sometimes been called Rumpelstiltskin attacks (named after the dwarf in the Grimms' fairy tale who tells a woman he will not hold her to a promise if she can guess his name--Rumpelstiltskin).
At least one major ISP makes dictionary attacks more difficult by limiting the number of RCPT TO: commands allowed in a single incoming "envelope". You can configure sendmail to impose the limitation by adding the following to your sendmail mc file:
define(`confMAX_RCPTS_PER_MESSAGE', `25')dnl(substituting your own preferred maximum for the `25' used above).
If (for example) the maximun is configured at 25 and the sender specifies a 26th recipient, sendmail will respond with
452 4.5.3 Too many recipientsIf the sending server ignores the 452 response and continues issuing RCPT TO: commands, the receiving sendmail will send the same response to all remaining RCPT TO: commands. Then, when the sender issues the DATA command and completes the message envelope, the message will be delivered only to the first 10 (in this example) recipients.
The idea here is that RFC-compliant sending servers will detect the temporary failure(s) and queue the message for later delivery to the temporarily rejected recipients. A spammer or trojan will likely never retry the failed recipients.
Caution: Remote mail users that specify your sendmail server as their outgoing SMTP server are subject to the same constraints as incoming SMTP servers that connect to your server: If you limit the maximum recipients to 25 and a user sends a message to 26 users via your sendmail server, sendmail will respond with a (possibly hard-to-understand) temporary failure. You should therefore set the number high enough to accomodate legitimate client senders but low enough to discourage dictionary attackers.
"Bad" recipients are those that your server doesn't receive mail for--addresses not listed in virtusertable, aliases, /etc/passwd (or whatever mechanism(s) your server uses for identifying legitimate recipients).
I have heard of some sites that block no mail, but instead route mail for unknown recipients to /dev/null. This seems like a particularly bad idea to me. Not only are spammers and attackers lead to believe that all their mail is being delivered, but legitimate senders that mistype the recipient's address receive no notification that the e-mail they sent was delivered to the "bit bucket."
Use of the option described in this section requires that mail to unknown users be rejected during the SMTP conversation.
You can tell sendmail to respond more slowly to the incoming server after a specified number of unknown recipient addresses have been specified, by inserting the following line in your mc file:
define(`confBAD_RCPT_THROTTLE',`num')dnlIf, for example, you specify num as 2, sendmail will respond normally to the first RCPT TO: commands. As soon as 2 unknown users have been identified, sendmail will record the following in the mail log:
Possible SMTP RCPT flood, throttling.and sleep for one second (hardcoded) after all subsequent RCPT TO: commands.
When an incoming mail server connects to yours, it is supposed to wait for your server's welcome greeting before commencing the SMTP conversation with the EHLO or HELO command. It is common for attackers and poorly written trojans and viruses to send the EHLO/HELO command without waiting for your server's greeting. The practice of not waiting for the greeting is called "slamming."
There are rumors that at least one large ISP's servers practice slamming. If you identify such an ISP, you can whitelist it in your access database (See below.)
The greet_pause feature (new in sendmail 8.13) causes sendmail to pause for a specified period of time at the beginning of the connection, before returning its greeting. If the incoming server issues the EHLO/HELO command during the pause, then sendmail will issue something like the following
554 mail.whipple.org not accepting messagesinstead of the standard greeting
220 mail.whipple.org ESMTP Sendmail 8.13.3/8.13.3; Thu, 3 Mar 2005 18:16:23 GMTand an entry is written to the mail log:
rejecting commands from 169.sub-166-180-49.myvzw.com [184.108.40.206] due to pre-greeting traffic
The following line (inserted in sendmail's mc file) will cause sendmail to pause a default 700 milliseconds before issuing its greeting:
If you omit the second argument (using just FEATURE(`greet_pause') in the mc file), or if you want to override the default, then you need to add entries to the access database. In the following example
GreetPause:host.domain.com 5000 GreetPause:domain.com 0 GreetPause:127.0.0.1 0 GreetPause:192.168.120 5000the first and last lines will force a greet pause of 5 seconds (5000 milliseconds); the second and third lines tell sendmail not to wait at all.
All other connecting hosts (or domains or addresses or networks) will have to wait the default time specified as the second argument to the FEATURE macro. (If the second argument was omitted from the FEATURE macro, hosts that don't match any access db GreetPause-tagged lines will not have to wait).
RFC 2821 specifies 5 minutes as the maximum timeout for the initial connection greeting. Therefore, if you specify a time longer than 300000 milliseconds (i.e. 5 minutes), sendmail will not wait longer than 5 minutes, to maintain RFC compliance.
Strictly speaking, this section is beyond the scope of this document. As you think about protecting your sendmail server, however, you will likely want to consider the following:
Hint: My current favorite DNS blacklist--if I were forced to use only one--is sbl-xbl.spamhaus.org
I scan (for viruses and spam) only the mail that gets past my DoS-blocking measures, DNS blacklists, access db entries and greylisting milter. This cuts down on server load required by the relatively CPU-intensive content scanning.
In an e-mail dated 30 Aug 2007, David Cook reported shortening the defaults significantly in his configuration file. You can implement his shortened timeout defaults by adding the following lines to the sendmail mc file and regenerating the cf file:
define(`confTO_INITIAL', `30s')dnl define(`confTO_CONNECT', `30s')dnl define(`confTO_ACONNECT', `1m')dnl define(`confTO_ICONNECT', `30s')dnl define(`confTO_HELO', `30s')dnl define(`confTO_MAIL', `30s')dnl define(`confTO_RCPT', `30s')dnl define(`confTO_DATAINIT', `1m')dnl define(`confTO_DATABLOCK', `1m')dnl define(`confTO_DATAFINAL', `1m')dnl define(`confTO_RSET', `30s')dnl define(`confTO_QUIT', `30s')dnl define(`confTO_MISC', `30s')dnl define(`confTO_COMMAND', `30s')dnl define(`confTO_CONTROL', `30s')dnl define(`confTO_LHLO', `30s')dnl
David reports that
each spammer was making several persistant connections to my server. ... While 'ratecontrol' 'connrate' helped to a degree, I found that changing the timeouts literally killed the problem dead. ... All other timeouts were left as is. Considering that some of the above defaults were in DAYS or HOURS, the above settings are pretty restrictive (but really, in todays internet should a single email exchange take 30 seconds to a minute?)
I have personally used most of the techniques discussed above, so I know that they work--on my server, at least. If you decide to implement them on your server, be careful to avoid typos. You will probably want to keep a backup copy of your old configuration file in case a rollback is necessary. After configuring any of the features and options described above, be sure to send test messages and monitor the mail logs to make sure that sendmail behaves as expected.
Feel free to report errors or omissions, or to suggest additions. Good luck!