Installing and automating ClamAV on macOS

18 August 2017


What’s going down

ClamAV is anti-virus software developed by Cisco. It runs on macOS, the BSDs, Linux, Windows etc.

Even though you’re obviously exercising caution in your daily computing, sometimes it’s worth scanning for software to see if you’ve picked up any malware, even if it hasn’t been able to affect you.

All of the ClamAV setup can be found in the manual.

Throughout, the macOS directory Users can be substituted by home on BSD or Linux and use of $ means that you type what follows.

Manual

To view the manual at any time, just man clamscan or use the link above.

Install

Installation is easier with Homebrew.

$ brew install clamav
Create and edit configuration files
$ cd /usr/local/etc/clamav
$ cp freshclam.conf.sample freshclam.conf
$ vi freshclam.conf

Comment/Uncomment the following lines, so they look like this:

# Example
SubmitDetectionStats /var/logs/clamav
Update database
$ freshclam

If the output is OK, create a log file in /var/log (owned by clamav or another user freshclam will be running as):

$ touch /var/log/freshclam.log
$ chmod 600 /var/log/freshclam.log
$ chown clamav /var/log/freshclam.log

Then run the following to start the freshclam daemon:

$ freshclam -d

However, we may find that we get the error:

ERROR: Can't open /var/log/freshclam.log in append mode (check permissions!).
ERROR: Problem with internal logger (UpdateLogFile = /var/log/freshclam.log).

In which case, we need to edit the following file and comment out the lines so they appear as indicated:

$ vi /usr/local/etc/clamav/freshclam.conf
DatabaseOwner clamav
UpdateLogFile /var/log/freshclam.log

We need to make a similar edit to clamd.conf, but first we need to make it from the provided sample:

$ cd /usr/local/etc/clamav
$ cp clamd.conf.sample clamd.conf

$ vi clamd.conf
User clamav
chown clamav:wheel clamd.conf freshclam.conf

This will run the daemon in the background – until shutdown. To make it persist, it’s suggested to use cron and have it run 2+ times per hour. This is fine for BSD and Linux environments but, seeing as cron’s deprecated in macOS, we ought to be using launchd. To run under cron, you have to add the following to the crontab of either root or the user clamav, where ‘N’ is the minutes past the hour at which you want the task to run:

N * * * * /usr/local/bin/freshclam --quiet

The launchd approach is to paste the following into a LaunchDaemon located at /Library/LaunchDaemons, named something like com.personal.freshclam.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.personal.freshclam</string>
    <key>ProgramArguments</key>
	<array>
	    <string>/usr/local/bin/freshclam</string>
		<string>-d</string>
	</array>
    <key>KeepAlive</key>
    <false/>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
        <integer>1800</integer>
</dict>
</plist>

This will run every 30 minutes and check for updates to the database.

Now start the freshclam service:

$ sudo launchctl load /Library/LaunchDaemons/com.personal.freshclam.plist

To check if it’s launched:

$ sudo launchctl list | grep com.personal.freshclam

There should be an item listed as follows, which indicates that: the job is loaded; the pid (currently ‘-‘ as it’s not running) and the exit code (0 is successful, positive is an error, negative means it was terminated after a termination signal):

-	0	com.personal.freshclam

And to check that it’s actually updated the av database:

$ ls -l freshclam.log

The file should have been updated in the last minute, or when you loaded the LaunchDaemon.

Scanning

Running a full system scan uses the familiar layout of command flags target, flags -r is recursive, –bell shows a Terminal bell when an infection is found and -i will only print the infected files.

$ clamscan -r --bell -i /

The output will show you any infected files, with their locations.

Other options are available, such as the flag --move=/Users/[username]/quarantine which moves viruses to a specified location.

Dealing with infections

When an infection is found, the options depend on which flags you used previously. ClamAV’s --remove flag should remove any infections during the scan. This can be dangerous (and even carries a warning in the manual) as it can/will remove files that an infection is part of. It re-runs the scan and deals with the infections as it finds them.

$ clamscan -r --remove /Users/[username]

Alternatively, if you used the --move flag then you could go straight to the specified folder and remove them manually. Lastly, you can just read the locations from the output.

Automated daily scans

The next thing to do is make sure all this is automated so it runs in the background without input. We’ll write a script, courtesy of centosblog.

$ vi ~/scripts/ClamAV
SCAN_DIR="/Users"
LOG_FILE="/var/log/clamscan.log"
echo `date +%F-%H%M` >> $LOG_FILE
/usr/local/bin/clamscan -i -r --move=/Users/[username]/quarantine $SCAN_DIR >> $LOG_FILE
# on BSD/Linux the location might be /usr/bin, so instead:
/usr/bin/clamscan -i -r --move=/home/[username]/quarantine $SCAN_DIR >> $LOG_FILE

The script needs to be executable:

$ chmod u+x ~/scripts/ClamAV

Finally, since we told it to write a logfile in /var/log we need to make sure it can be written, so create the file and set the permissions on it to match the user who will be running the script:

$ sudo touch /var/log/clamscan.log
$ sudo chown [username]:[group] /var/log/clamscan.log

Now, for BSD/Linux we just need to install it to crontab and make sure it runs regularly:

$ crontab -e
05	*	*	*	*	~/scripts/ClamAV

Or, for macOS, it’s back to launchd:

$ sudo vi /Library/LaunchDaemons/com.personal.clamav.plist

And paste:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.personal.clamscan</string>
    <key>Program</key>
    <string>/Users/[you]/Scripts/clamscan</string>
    <key>KeepAlive</key>
    <false/>
    <key>RunAtLoad</key>
    <false/>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>18</integer>
        <key>Minute</key>
        <integer>28</integer>
    </dict>
    <key>StandardErrorPath</key>
    <string>/var/log/clamscan.stderr</string>
</dict>
</plist>

Finally, let’s just make sure we get system emails telling us if there’s anything found. First, we write a simple script named clam-mail located at ~/Scripts:

echo "There are new items for review in /Users/[you]/tmp/quarantine" | mail -s "URGENT! Clamscan Found Infections!" root

This will send an email to root using the postfix setup process that we’ve already been through. Then we create the LaunchDaemon:

$ sudo vi /Library/LaunchDaemons/com.personal.clammail.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.personal.clammail</string>
    <key>ProgramArguments</key>
	<array>
		<string>/Users/[you]/Scripts/clam-mail</string>
	</array>
    <key>WatchPaths</key>
    <array>
        <string>/Users/[you]/tmp/quarantine</string>
    </array>
    <key>AbandonProcessGroup</key>
    <true/>
	<key>StandardErrorPath</key>
    <string>/var/log/clamscanqmail.stderr</string>
</dict>
</plist>

What this last daemon does is watches the directory specified under WatchPaths and as soon as there’s any modification of that directory it will send an email to root. Test it, to make sure it’s all working (you should receive an email warning you of infections):

$ touch /Users/you/tmp/quarantine/test.txt

Sources