Automated ClamAV Virus Scanning

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 / -not -wholename '/sys/*' -and -not -wholename '/proc/*' -mmin -61 -type f -print0 | xargs -0 -r clamscan --exclude-dir=/proc/ --exclude-dir=/sys/ --quiet --infected --log=${LOG}
check_scan

find / -not -wholename '/sys/*' -and -not -wholename '/proc/*' -cmin -61 -type f -print0 | xargs -0 -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.

19 thoughts on “Automated ClamAV Virus Scanning

  1. Nice scripts – thanks for posting them. One problem – filenames with spaces. Example:”Time_spent on the queue-all messages.png”

    Naturally, you get the following complaint:

    Time_spent: No such file or directory
    on: No such file or directory
    the: No such file or directory
    queue-all: No such file or directory
    messages.png: No such file or directory

    :)

      • Very good point! Assuming you’re only having the issue with the hourly script, it’s not clam’s fault, it’s mine/linux’s:) However, I’ve just updated the hourly script in a way that should handle files with spaces no problem. Give it a test!

        Thanks!

        Devon

  2. Hi Devon,
    Thanks for these great scrips! Very, very useful.

    Two comments that may be helpful: when using -type f I did not pick up viruses in zip files but as soon as I removed -type f altogether, I did find them. Also, the hourly script above runs ‘find’ and ‘clamscan’ twice.

    cheers

    • Good point on the -type f thing. I didn’t check that. The twice running thing is by design, but I had a cut and paste failure when I updated that script. It should run once for -mmin and once for -cmin to find both files created in the last 61 minutes, and files modified in the last 61 minutes. Fixing the script now, good eye!

  3. I implemented the scripts for daily and weekly scans, though I have a question regarding the log file setup.

    When I first tried to use the LOG option from the command line, I found that I had to create the scan.log file manually.

    My question is how did you setup the log file permissions so that the cron script will write to it?

    • It should run as root, so it shouldn’t need any special permissions. Just make sure the scan.log file is owned by root, and it can be world readable without too much risk.

      Devon

  4. The find command can list files that match on separate criteria, i.e. or/union. This should list the same files as your two-pass approach in one pass, without duplicates:

    find / \( -wholename ‘/proc’ -o -wholename ‘/sys’ \) -prune -o -type f \( -cmin -61 -o -mmin -61 \) -print0

  5. Hi There

    When the hourly cron runs, I get the following e-mail:

    /etc/cron.hourly/clamscan_hourly:

    /etc/cron.hourly/clamscan_hourly: line 33: unexpected EOF while looking for matching `”
    /etc/cron.hourly/clamscan_hourly: line 37: syntax error: unexpected end of file

    Can you please help me to resolve.

    Thanks

  6. Can u please explain me what is the hourly script doin in

    find / -not -wholename ‘/sys/*’ -and -not -wholename ‘/proc/*’ -mmin -61 -type f -print0

    I wanna understand why this so solution is performing so well. Thank u !

    • Sure. Basically this is finding files which have been modified in the past 61 minutes, ignoring files under /sys/ and /proc/ which are often file representations of system data/ports/etc… and will show up as changed all the time but be unscanable/slow to scan/etc…

      By checking only files created or changed in the past hour the hourly scan can quickly check for potential new viruses, without doing a full hard drive scan, which happens nightly just in case.

      • ah ok thank u for the explanation!

        i still workin on getting clamd startet for scanning files on-access. while beeing an linux-noob i cannot get clamd reacting on uploaded test files. clamdscan is working but the daemon itself doesnt react on infected files, dont know what to do so… :(

        • What do you want it to do? Using my scripts it will just e-mail you if a scan finds something, leaving you to take manual action. You can configure clam to automatically delete or quarantine flagged files as well, but that’s something you should read the clamav docs for.

  7. Would there be any way that the clamscan_daily script can be put on the same site where the clamscan_hourly script was? The site where you could paste directly from. Having trouble getting the daily script to work properly. Getting the error: /etc/cron.daily/clamscan_daily: line 9: syntax error: unexpected end of file and: /etc/cron.daily/clamscan_daily: line 7: unexpected EOF while looking for matching `”

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>