[RELEASE] SpamBlocker released

Titam said:
I installed it, and now i have something strange.
Just what did you install, Titam?

demime doesn't appear anywhere in the SpamBlocker exim.conf file.

Jeff
 
Automatically add spammers to firewall?

SpamBlocker has worked wonders on my inbox. My spam folder in Thunderbird is down from 120-150 spams daily to <10 most days. That's a total from about 10 email addresses over three separate domains. Thanks Jeff!

Looking through the logs, I can see that a few machines are responsible for most of the attempted spam that hits my server. I see dozens of dictionary attacks each day, attempting to email dozens (or hundreds) of people at a given domain using common names. Most of this spam is blocked and does not get to my users, but it still annoys me. I'm sure that it's using some resources to check those RBLs and send out the error message.

I'd like to have those servers automatically added to my firewall rules to block them even before they hit the mail server. I've seen similar rules set up for a server that tries a dictionary attack on FTP or SSH logins - more than x login attempts in y minutes and you're firewalled, at least for a while. I could write a bash script of some sort that would parse the mail log and count the bounces from each server to add them to the firewall rules, but the only way I can think to do it would involve running this script on a cron every so often. It seems to be that it would be better to do this somehow through Exim/SpamBlocker. I'm not sure that the resources necessary to grep through the mail logs would justify the savings.

Adding a machine to the firewall could have unintended consequences...if the machine is one of my clients whose local machine is infected, I'm sure I would hear about it. I think that's a risk I'm willing to take at the moment. Perhaps in the long term, however, it would be better to add the domains to one of the blacklist files as those are apparently read before consulting the RBLs.

So, my questions:

-How much of my resources are being used by the hundreds of emails that SpamBlocker is rejecting? I know it's impossible to give a specific answer to that question, but is it more/less resource intensive than blocking a host at the firewall? Would there be a significant difference if a host were blocked at the firewall rather than the mail server?

-In terms of resources used, is there a significant difference between an email that's blocked in the local blacklist and one that's blocked by an RBL?

-Can you see a use in writing a bash script to automatically add the offending hosts to the blacklist or firewall rules?

-Is it possible to accomplish this in real-time directly through Exim, without the need for an additional script?
 
I wouldn't worry so much about you clients being blacklisted if they are infected, as a matter of fact, you should embrace that since it would help both you and them. Once they get blacklisted, you could inform them why and they could clean up their machine saving them a lot of future problems.

As for methodology...I'd go with a bash script myself, at least till something better can be found.

I need to actually write one that catches the bots that hit my server trying to find the common exploits...logs are full of them.
 
SpamBlocker uses a lot less resources than SpamAssassin.

But using the strict meaning of significantly, yes, SpamBlocker uses significantly more resources than a firewall block would use.

I've chosen to not do automatic adding to blocklists or firewall, but if you want to do it, I'd recommend a scriopt to run occasonally and make decisions based on the contents of /var/log/exim/rejectlog.

Jef
 
I wrote up a bash script to parse through the logs, and I've found one host that has attempted over 18000 (yes that's three zeroes) and counting entries in the reject log since the first of the month. That's roughly 270 per hour from one machine alone. From eyeballing the reject log I suspect it may be one of my clients, as the incoming messages are all sent to email addresses at his domain hosted on my server. In any case it's obviously a hacked box and I don't want it anywhere near my server.

I've put the script up for inspection here:
http://www.bluenoteweb.com/email_script/parse_email_logs

Any comments, questions or suggestions would be much appreciated. My bash scripting skills are not that great. So far this only puts the offending IPs into a log file, the next step is to add them to the firewall rules.
 
Looks good.

Be sure to update again in a few days letting us know how this is working for you.

Jeff
 
Here's a script I found on-line and implemented. It's designed to combat dictionary attacks. It does not directly modify your firewall script but it would be easy to make it do so if you wanted to. Personally, I liked this solution better.

It's a simple perl script that builds a text file of IP addresses. I've modified the SpamBlocker exim.conf file to check that file before allowing connections. Basically, the way it works is after 3 failed email addresses in a single connection, it shuts down the connection and adds the IP address to the text file. Before accepting any emails, the IP is checked against this file and rejected if found.

It's not fool proof and I go through and clean out the file about once a week. (One day I'll write a cron job that cleans it out nightly)

But it does work and some days I catch over 1,000 IP addresses that are trying to spam my server.

To implement:
1: Put dictscan.pl in your /etc dir. make sure mail owns it and can execute it.

2: touch /etc/exim_deny, again make sure mail owns it and can write to it.

edit your exim.conf file, find the check_recipient: ACL and put the code below in it. If you are using the latest SpamBlocker I put it right above the line:

# OPTIONAL MODIFICATIONS:

I hope it works as well for you as it does for me.

Oh and thanks Jeff for the great conf file. Truly, you rock.

=C=

---BEGIN dictscan.pl
#!/usr/bin/perl -w

use strict;

my $file = '/etc/exim_deny';

my $ip = shift;

die "No argument" unless defined $ip;

die "Invalid argument |$ip|" unless $ip =~ /^\d+\.\d+\.\d+\.\d+$/;

# (at this point you _could_ take a look in the file and see
# if the address is already there - can happen occasionally
# e.g when two concurrent dictionary-scan attacks are detected
# from the same IP).

# Since we're doing an append we can ignore file locking...
# (and it's not going to be the end of the world if we sometimes
# manage to list the same address twice...)

open OUT, ">>$file" or die "Couldn't open file, $!";

my $datestamp = scalar localtime;

print OUT "\n\# $datestamp\n$ip\n";

close OUT;
---END dictscan.pl

---modifications to the exim.conf file
#
# http://www.configserver.com/free/eximdeny.html
#
# If they added themselves to the file below, let's block them for Dict Scan!!!
deny message = Blocked because your address is being used for a dictionary attack.
hosts = /etc/exim_deny
!hosts = +relay_hosts
!authenticated = *
delay = 150s
log_message = Blocked because of dictionary scan.

deny message = Max $rcpt_fail_count failed recipients allowed
condition = ${if > {${eval:$rcpt_fail_count}}{2}{yes}{no}}
condition = ${run{/etc/dictscan.pl $sender_host_address}{1}{1}}
!hosts = +relay_hosts
delay = ${eval: ($rcpt_fail_count) * 30}s
log_message = Dictionary scan! $rcpt_fail_count failed recipient attempts
---END modifications to exim.conf.
 
OxnardMontalvo said:
Here's a script I found on-line and implemented. It's designed to combat dictionary attacks. It does not directly modify your firewall script but it would be easy to make it do so if you wanted to. Personally, I liked this solution better.
This looks quite good. I think you'd be better off putting it in a firewalling script (see APF/BFD for examples on how to do it) because firewall blocking is a lot more efficient than exim-based blocking. And the advantage is that you can clear the file with the same mechanism you use to clear BFD.
It's a simple perl script that builds a text file of IP addresses. I've modified the SpamBlocker exim.conf file to check that file before allowing connections. Basically, the way it works is after 3 failed email addresses in a single connection, it shuts down the connection and adds the IP address to the text file. Before accepting any emails, the IP is checked against this file and rejected if found.
I hope you don't mind me making a few comments:
1: Put dictscan.pl in your /etc dir. make sure mail owns it and can execute it.
Any unix/linux purist will tell you to never put executable code in your /etc directory. In fact many of us will mount /etc as it's own partition, non-executable. Variable files (files that may change) should be put under /var, and local files (files which are not part of the base OS distribution) should probably be put under local, so I'd put this kind of file under /var/local.

While I know that DA breaks the rules concerning variable files, and that I broke the rules when I wrote SpamBlocker (to match DA's breaking of the rules and put similar files in similar places), I don't think I want to put executable files directly into /etc.
hosts = /etc/exim_deny
!hosts = +relay_hosts
!authenticated = *
delay = 150s
log_message = Blocked because of dictionary scan.
This is probably more personal than anything else but I'd like to see hosts =!+relay_hosts instead of !hosts=+relay_hosts (and similarly for the rest of the conditions) as that's the way the rest of the conditions are written.

Additionally in my opinion the log file message and the error message should be the same, to help you find something in the log file, if the need arises, from email headers someone has sent back to you.

Jeff
 
jlasman said:
This looks quite good. I think you'd be better off putting it in a firewalling script (see APF/BFD for examples on how to do it) because firewall blocking is a lot more efficient than exim-based blocking. And the advantage is that you can clear the file with the same mechanism you use to clear BFD.

I thought about this and am still considering it for the same reason you pointed out. However, I want some mechanism that automatically unblocks an IP after 24 hrs. I'm thinking of modifying the script to block the IP and immediately issue an AT command to unblock it in 24 hrs. That way it's fire and forget.

I hope you don't mind me making a few comments:

You are just way to freakin polite. :)


Any unix/linux purist will tell you to never put executable code in your /etc directory. In fact many of us will mount /etc as it's own partition, non-executable. Variable files (files that may change) should be put under /var, and local files (files which are not part of the base OS distribution) should probably be put under local, so I'd put this kind of file under /var/local.
Yep and the guy who wrote this should be horse-whipped with me. I didn't think of /var but you are right, that's a better place for it. I was going to move it to /etc/virtual or /etc/mail.


Additionally in my opinion the log file message and the error message should be the same, to help you find something in the log file, if the need arises, from email headers someone has sent back to you.
Yes, that need to be cleaned up and standardized like the other block messages. I'm in the process of writing my /unblockme.php and when I finish with that my plan was to clean it up and make it look like the other blocks.

=C=
 
I like this dictscan thing, what I would do is make it just issue an iptables blah blah -j DROP but not actually add the ip to my global deny list so when apf restarts (once a day) it'll clear the ips blocked earlier that day.

As soon as an ip is blocked it should quit being able to access the server - so just add a bit to the script that basically says "if an ip is already IN my list that means it was blocked yesterday or some other day so let's email admin and let him know" and then if an ip repeatedly ends up in my list, I add him to the global block list that I keep on a remote server (all my servers use the same deny_list so I only have to edit one deny rule and all servers will block that ip).

Just some musings on it. If someone keeps on ending up on the temp block may as well just add him to the perm block and let him rot there.

My list is so long it takes apf like 4 minutes to restart haha.
 
Logrotate ran yesterday, so this morning I split the old Exim rejectlog into sub-logs by date. Check this out:

[root@beethoven exim]# /root/scripts/split_log rejectlog.1 2006 01 08
[root@beethoven exim]# ls -alh *.log
-rw-r--r-- 1 root root 188K Jan 9 07:42 01.log
-rw-r--r-- 1 root root 756K Jan 9 07:43 02.log
-rw-r--r-- 1 root root 1.4M Jan 9 07:43 03.log
-rw-r--r-- 1 root root 1.5M Jan 9 07:43 04.log
-rw-r--r-- 1 root root 1.4M Jan 9 07:43 05.log
-rw-r--r-- 1 root root 201K Jan 9 07:43 06.log
-rw-r--r-- 1 root root 220K Jan 9 07:43 07.log
-rw-r--r-- 1 root root 33K Jan 9 07:43 08.log
[root@beethoven exim]# ls -al *.log
-rw-r--r-- 1 root root 192512 Jan 9 07:42 01.log
-rw-r--r-- 1 root root 774445 Jan 9 07:43 02.log
-rw-r--r-- 1 root root 1429889 Jan 9 07:43 03.log
-rw-r--r-- 1 root root 1522519 Jan 9 07:43 04.log
-rw-r--r-- 1 root root 1423165 Jan 9 07:43 05.log
-rw-r--r-- 1 root root 206230 Jan 9 07:43 06.log
-rw-r--r-- 1 root root 225706 Jan 9 07:43 07.log
-rw-r--r-- 1 root root 34205 Jan 9 07:43 08.log

*.log is the log for that particular day of the month. The sizes of 01.log and 08.log are misleading because logrotate runs sometime in the morning, some of the entries from those dates are in other files.

Notice the difference from 05.log to 06.log - I first implemented the firewall script on the 5th. The size of my rejectlog from the 6th is 1/7th what it was on the 5th.
 
I like this dictscan script also - I think I may implement it. Those who attempt an attack are blocked immediately, if they ignore the bounces and try again they get firewalled when the cron runs. I like it.
 
OxnardMontalvo said:
I thought about this and am still considering it for the same reason you pointed out. However, I want some mechanism that automatically unblocks an IP after 24 hrs. I'm thinking of modifying the script to block the IP and immediately issue an AT command to unblock it in 24 hrs. That way it's fire and forget.



You are just way to freakin polite. :)



Yep and the guy who wrote this should be horse-whipped with me. I didn't think of /var but you are right, that's a better place for it. I was going to move it to /etc/virtual or /etc/mail.



Yes, that need to be cleaned up and standardized like the other block messages. I'm in the process of writing my /unblockme.php and when I finish with that my plan was to clean it up and make it look like the other blocks.

=C=



agreed , i too like to see this
 
I fired this up on a server that has a particularly bad problem with spam and since yesterday afternoon (not even 24 hours yet) it's added 7448 ips to the exim_deny list.

I modified the script to use 7 instead of 3 failed messages to make it even harder to be added! And still over 7400 ips in under 24 hours!
 
jlasman said:
This looks quite good. I think you'd be better off putting it in a firewalling script (see APF/BFD for examples on how to do it) because firewall blocking is a lot more efficient than exim-based blocking. And the advantage is that you can clear the file with the same mechanism you use to clear BFD.


Ok, I've thought about this for quite some time and even tinkered with the code for a few hours. Regarding having the firewall block the IP I have the following thoughts:

1: One of the things that makes this solution so effective for my setup is the immediacy of the block. In looking at my log files, after 48 hours I don't see traffic from a blocked IP address. I am assuming that because most of these machines are zombies, I see a lot of traffic from one and then it goes away and another one takes it's place. If I wait until the end of the evening and analyze the log files to see what I should block, a lot of spam gets through.

2: Exim runs as the mail user. I use APF for my firewall script. To make it work within exim, I have to make it so the mail user can execute a lot of stuff I'm not comfortable letting it execute.

3: This configuration still allows legitimate users who 'accidentally' sent mail to 3 bad users on my system, still have a chance and getting themselves unblocked because the only service that won't talk to them is exim.

So while I do take a hit by exim having to make this call, my mail volume is low enough (10k msg a day or less) that it doesn't really matter.

YMMV.

=C=

Cal Evans
http://blog.calevans.com
 
Since: # Thu Jan 12 00:25:01 2006

ONE server, 200 websites, has recorded 14,824 UNIQUE IP's it's flagged as "dictionary attacks". 6 hours ago that number was 14,341. 6 hours - 500 new IP's.

http://www33.hostpc.com/exim_deny

I can't even imagine the time it would take APF or KISS to parse that log every time it was updated.
 
hostpc.com said:

I can't even imagine the time it would take APF or KISS to parse that log every time it was updated.

The approach I was using was to have the replacement for dictscan.pl (a bash script) fire IPTABLES with the proper command to add an IP into the deny chain. (NOt sure if I'm using the right terminology) I wasn't going to store it for later use. Then I wanted to use the AT command to remove it from memory in 24 hours. If APF or the box got rebooted, it would start with a clean list. In theory it would solve the problem of having to parse a huge list.

However, it does't solve the problem of IPTABLES haivng to deal with an extremely large (and in your case, constantly changing) deny chain.

Would exim perform better if the list were sorted? It wouldn't take much to sort it every hour if that would make a difference in speed.

IMHO, etc.

=C=
Cal Evans
http://blog.calevans.com
 
Exim won't perform as well as firewalling.

Firewalling might be harder to set up and manage, but it's worth it in the long run.

Jeff
 
jlasman said:
Exim won't perform as well as firewalling.

Firewalling might be harder to set up and manage, but it's worth it in the long run.

Jeff

Jeff,

I know in general that is true. However, my hesitation, aside from the points I've already posted is this. Given the number of packets a firewall analyzes vs. the number of emails exim check an IP for before accepting, my gut feeling is that I expend fewer CPU cycles overall filtering from within exim than I do if I start adding these checks to my firewall.

I'm the first to admit that I may be wrong in my logic here. Given your work in this area, I do bow to your knowledge in the subject.

IMHO, etc.

=C=
Cal Evans
 
Last edited:
Back
Top