Site Network: Personal | Professional | Photography

Technical Blog

This blog will contain content related to Java, Seam, Security, my sites and projects, as well as other technical subjects I am interested in.

Comments and questions are welcome!

Automated ClamAV Virus Scanning

Tuesday, January 26th, 2010

Automating Linux Anti-Virus Using ClamAV and Cron

Thankfully Linux isn’t a platform which has a significant problem with Viruses, however it is always better to be safe than sorry. Luckily ClamAV is an excellent free anti-virus solution for Linux servers. However, at least on RedHat Enterprise 5 (RHEL5) the default install doesn’t offer any automated scanning and alerting. So here is what I’ve done:

The following steps assume you are using RHEL5, but should apply to other Linux distributions as well.

First, you’ll want to install ClamAV:

yum install clamav clamav-db clamd
/etc/init.d/clamd start

On RHEL5 at least this automatically sets up a daily cron job that uses freshclam to update the virus definitions, so that’s good.

Next I recommend removing the test virus files, although you can save this until after you test the rest of the setup:

rm -rf /usr/share/doc/clamav-0.95.3/test/

Now we want to setup our automation. I have a daily cron job that scans the entire server which can take several minutes, and then an hourly cron job that only scans files which were created or modified within the last hour. This should provide rapid notification of any infection without bogging your server down for 5 minutes every hour. The hourly scans run in a couple of seconds.

Each scanning script then checks the scan logs to see if there were any infected files found, and if so immediately sends you a notification e-mail (you could set this address to your mobile phone’s SMS account if you wanted).

The Daily Scan:

emacs /etc/cron.daily/clamscan_daily

Paste in:

#!/bin/bash

# email subject
SUBJECT="VIRUS DETECTED ON `hostname`!!!"
# Email To ?
EMAIL="me@domain.com"
# Log location
LOG=/var/log/clamav/scan.log

check_scan () {

	# Check the last set of results. If there are any "Infected" counts that aren't zero, we have a problem.
	if [ `tail -n 12 ${LOG}  | grep Infected | grep -v 0 | wc -l` != 0 ]
	then
		EMAILMESSAGE=`mktemp /tmp/virus-alert.XXXXX`
		echo "To: ${EMAIL}" >>  ${EMAILMESSAGE}
		echo "From: alert@domain.com" >>  ${EMAILMESSAGE}
		echo "Subject: ${SUBJECT}" >>  ${EMAILMESSAGE}
		echo "Importance: High" >> ${EMAILMESSAGE}
		echo "X-Priority: 1" >> ${EMAILMESSAGE}
		echo "`tail -n 50 ${LOG}`" >> ${EMAILMESSAGE}
		sendmail -t < ${EMAILMESSAGE}
	fi

}

clamscan -r / --exclude-dir=/sys/ --quiet --infected --log=${LOG}

check_scan
chmod +x /etc/cron.daily/clamscan_daily

The Hourly Scan:

emacs /etc/cron.hourly/clamscan_hourly

Paste in:

#!/bin/bash

# email subject
SUBJECT="VIRUS DETECTED ON `hostname`!!!"
# Email To ?
EMAIL="me@domain.com"
# Log location
LOG=/var/log/clamav/scan.log

check_scan () {

	# Check the last set of results. If there are any "Infected" counts that aren't zero, we have a problem.
	if [ `tail -n 12 ${LOG}  | grep Infected | grep -v 0 | wc -l` != 0 ]
	then
		EMAILMESSAGE=`mktemp /tmp/virus-alert.XXXXX`
		echo "To: ${EMAIL}" >>  ${EMAILMESSAGE}
		echo "From: alert@domain.com" >>  ${EMAILMESSAGE}
		echo "Subject: ${SUBJECT}" >>  ${EMAILMESSAGE}
		echo "Importance: High" >>; ${EMAILMESSAGE}
		echo "X-Priority: 1" >> ${EMAILMESSAGE}
		echo "`tail -n 50 ${LOG}`" >> ${EMAILMESSAGE}
		sendmail -t < ${EMAILMESSAGE}
	fi

}

find / -mmin -61 -type f | grep -v '/proc/' | grep -v '/sys/' | xargs -r clamscan --exclude-dir=/proc/ --exclude-dir=/sys/ --quiet --infected --log=${LOG}
check_scan

find / -cmin -61 -type f | grep -v '/proc/' | grep -v '/sys/' | xargs -r clamscan --exclude-dir=/proc/ --exclude-dir=/sys/ --quiet --infected --log=${LOG}
check_scan
chmod +x /etc/cron.hourly/clamscan_hourly

Protected System

You should now have a well protected system with low impact to system performance and rapid alerting. Anti-Virus is only one piece of protecting a server, but hopefully this makes it easy to implement for everyone.

Why I love Debian (and PostgreSQL)

Tuesday, June 17th, 2008

I woke up this morning, got online through my new UMTS/HSPDA modem, and discovered that one of my servers had a load average of 239+

Not the best way to start the day.

Turns out an rsync backup job between two servers had gone nuts and was spinning them up through the roof. A couple

sudo killall rsync

commands, and everything started settling down.

What’s important to note is that while the CPU was pegged, and the load average was over 200, I was still able ssh in, run top, ps, netstat, and navigate around looking at log files, with very little delay. It was just a little slow, but no more than a second wait for anything.

Also, all of my apps which used MySQL as their backend were all dead, with “database refused connection” errors. All of my apps which used PostgreSQL as their backend were a little slow, but were all still up and functioning without errors.

So, Debian and PostgreSQL for the win!

Using IPTables to Prevent SSH Brute Force Attacks

Saturday, May 24th, 2008

If you have a server with a world facing ssh server, you’ve probably seen brute force attacks in your logs. Some machine starts hammering your ssh server, trying all sorts of logins (staff, root, a, admin, etc…) over and over and over again.

This is bad on a lot of fronts.

I use two simple iptables rules to block any IP address who has made more than 3 ssh connections or attempted connections within the past 3 minutes. So your would-be brute force attacker, gets three tries, and then is locked out for a minimum of three minutes. However, since 99% of the attacks are run by an automated bot, it will either: give up after the connection is refused multiple times, or it will keep hammering away on the closed door, which keeps the running count of attempted connections in the past 3 minutes over 3, keeping the door closed.

First:

iptables -I INPUT -i eth1 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name DEFAULT --rsource

Then run:

iptables -I INPUT -i eth1 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 180 --hitcount 4 --name DEFAULT --rsource -j DROP

I’d also recommend using the script in my post on blocking IP addresses using iptables to deal with any persistent folks, or people poking too hard on your web site, or other services.