« Hand Drills and the Art of House Building | Main | Software review: djbdns »
novembre 9, 2004
Simple email virus scanning with Sanitizer and ClamAV
This article is the result of hours of trying to figure out how to clean up my email box. I was tired of receiving several spams and virii every day. I managed to set up spamassassin pretty easily, but I had several frustrating problems with automated antivirus email scanning.
Note that this article was written in 2003, so it might not be accurate anymore. By the way, I'm now using qpsmtpd to scan my incoming mail.
Simple email virus scanning with Sanitizer and ClamAV
I spent several hours trying to make Amavis work, at times it would even eat my emails without saying anything. When I finally managed to make it work on my system, its daemon would use 18 MB of RAM, which is a lot for a program that only starts an external antivirus program.
I finally abandoned Amavis and searched for something else that would simply work (and work simply). Surprisingly, it only took me about half an hour on Google to find out what I was looking for. Should I have done that before trying Amavis, it would have saved me of lot of pain. Here's what I found.
Anony Sanitizer
Anony Sanitizer is a relatively simple perl script that is called from procmail, it is designed to manage email attachments. It decides what to do with them depending on their filenames using regular expressions. It works with an external antivirus program, it is really easy to make it work with about any command line virus scanner out there.
Here's the formal description available on its web site.
The Anomy sanitizer is what most people would call
an email virus scanner. That description is not totally accurate, but it does cover one of the more important jobs that the sanitizer can do for you - it can scan email attachments for viruses. Other things it can do:
- Disable potentially dangerous HTML code, such as javascript, within incoming email.
- Protect you from email-based break-in attempts which exploit bugs in common email programs (Outlook, Eudora, Pine, ...).
- Block or "mangle" attachments based on their file names. This way if you don't need to receive e.g. visual basic scripts, then you don't have to worry about the security risk they imply (the ILOVEYOU virus was a visual basic program). This lets you protect yourself and your users from whole classes of attacks, without relying on complex, resource intensive and outdated virus scanning solutions.
The sanitizer is designed not to waste important system resources (CPU, memory, disk space) unnecessarily, and does so by treating it's input as a stream which is scanned and rewritten a little bit at a time.
One of the core ideas behind the design of the sanitizer, is that just because a message contains an infected attachment doesn't mean that the rest of it shouldn't be delivered. Email often contains important information, and it is vital that a tool like this interrupt the normal flow of communication as little as possible. It's common courtesy to inform the user of any changes that are made. The Anomy sanitizer tries to follow these rules.
The sanitizer is based on solid foundations - most of the ideas implemented in the first versions of the sanitizer were ported from John D. Hardin's
email security through procmailpackage. The sanitizer, like the code it is based on, is Free Software in the GNU sense of the term - the sanitizer may be modified and redistributed according to the terms of the GNU General Public License.Sanitizer development is for the most part sponsored by FRISK Software International. Please consider buying their anti-virus products to show your appreciation.
Now that I had something to parse the messages and fire up the antivirus, I only needed an antivirus program.
Clam AntiVirus
I spent a lot of time trying every antivirus program listed on Amavis' web site and was disappointed by every single one of them. I finally found satisfaction when searching on packages.debian.org, where I found Clam AntiVirus (ClamAV for short).
ClamAV is a simple antivirus program using the OpenAntiVirus.org virus signatures. It's written in C and, like Sanitizer, it's licensed under the GPL. In my humble opinion, the only thing it lacks is a way to repair infected files like other antivirus programs do.
Here's the formal description from its web site.
Clam AntiVirus is an anti-virus toolkit for UNIX. The main purpose of this software is the integration with mail servers (attachment scanning). The package provides a flexible and scalable multi-threaded daemon, a command line scanner, and a tool for automatic updating via Internet. The programs are based on a shared library distributed with the Clam AntiVirus package, which you can use in your own software. Clam AV uses a virus database from OpenAntiVirus.org, we also help with signature generating.
Installation
I did the installation on Debian so I just ran apt-get install sanitizer clamav clamav-testfiles and everything was installed and configured.
On other systems, you may have to use RPMs or to compile the source, check out ClavAV docs and Sanitizer docs for more information.
Configure Clam Antivirus
On Debian this step is done by the installer, but you'll have to do it manually for other operating systems.
The only thing you need to do to configure Clam Antivirus is to have its virii signatures downloaded every night.
Set up a cronjob to start this every night:
sudo -u clamav /usr/bin/freshclam --quiet -l /var/log/clam-update.log
The definitions will be saved to directory /var/lib/oav-virussignatures
Test ClamScan
To make sure that your Antivirus installation is working correctly, do the following steps.
ali:# cd /usr/share/clamav-testfiles/ ali:# /usr/bin/clamscan --recursive --unzip --unrar --tar --tgz Archive: /usr/share/clamav-testfiles/test2.zip inflating: clamtest /tmp/fe5346b6358e37b5/clamtest: ClamAV-Test-Signature FOUND /usr/share/clamav-testfiles/test2.zip: Infected Archive FOUND /usr/share/clamav-testfiles/README: OK /usr/share/clamav-testfiles/test1: ClamAV-Test-Signature FOUND /usr/share/clamav-testfiles/ha: OKUNRAR 2.71 freeware Copyright (c) 1993-2000 Eugene Roshal
Extracting from /usr/share/clamav-testfiles/test3.rarExtracting test2.zip Ok
All OK
Archive: /tmp/5928df3a8015eea3/test2.zip
inflating: clamtest
/tmp/b1c9441d58318672/clamtest: ClamAV-Test-Signature FOUND
/tmp/5928df3a8015eea3/test2.zip: Infected Archive FOUND
/usr/share/clamav-testfiles/test3.rar: Infected Archive FOUND----------- SCAN SUMMARY -----------
Known viruses: 7271
Scanned directories: 4
Scanned files: 5
Infected files: 3
Data scanned: 0.00 Mb
I/O buffer size: 131072 bytes
Time: 2.403 sec (0 m 2 s)
If it reports 3 infected files like in the example above, then it is working properly. You can remove the clamav-testfiles if you want, they won't be needed anymore.
Configure Sanitizer
Sanitizer works with policies, you define policies for attachments depending on their filenames -- mainly their extension -- using regular expressions. The actions that you can do for each policy is: Accept, Mangle, Save or Drop.
I decided to define two simple policies:
- Drop any attachment of type: pif, com, cmd, bat
- Scan any attachment of type: exe, zip, tar, tgz, tar.gz, rar, doc, xls, pps, ppt
- Drop it if it contains a virus
- Accept it if it didn't contained a virus
- Save it in quarantine in case of an error.
The default policy is to accept attachments.
This policy is quite lax, that's what I wanted, you may want to make your policy more strict.
Here's the Sanitizer configuration (/etc/sanitizer.conf) file that I'm using.
#
# All feature switches.
#
header_info = X-Virus-Scanned: Scanned by Sanitizer/ClamAV
header_url = 0 # Don't show the Mailtools URL
feat_verbose = 0 # Warn user about unscanned parts, etc.
feat_log_inline = 1 # Inline logs: 0 = Off, 1 = Maybe, 2 = Force
feat_log_stderr = 0 # Don't print log to standard error
feat_log_xml = 0 # Don't use XML format for logs.
feat_log_trace = 0 # Omit trace info from logs.
feat_log_after = 0 # Don't add any scratch space to part headers.
feat_files = 1 # Enable filename-based policy decisions.
feat_force_name = 0 # Dont't force all parts (except text/html parts) to
# have file names.
feat_boundaries = 0 # Don't replace all boundary strings with our own
# NOTE: Always breaks PGP/MIME messages!
feat_lengths = 1 # Protect against buffer overflows and null
# values.
feat_scripts = 1 # Defang incoming shell scripts.
feat_html = 1 # Defang active HTML content.
feat_webbugs = 1 # Web-bugs are allowed.
feat_trust_pgp = 0 # Don't scan PGP signed message parts.
feat_uuencoded = 1 # Sanitize inline uuencoded files.
feat_forwards = 1 # Sanitize forwarded messages
feat_testing = 0 # This isn't a test-case configuration.
feat_fixmime = 1 # Fix invalid MIME, if possible.
feat_paranoid = 0 # Don't be excessively paranoid about MIME headers
# Create temporary or saved files using this template.
# An attachment named "dude.txt" might be saved as
#
# /var/quarantine/att-dude-txt.A9Y
#
# Note: The directory must exist and be writable by
# the user running the sanitizer.
#
file_name_tpl = /var/quarantine/att-$F.$$$
#
# Policies
#
# We have two policies, in addition to the default which is
# to accept attachments.
file_list_rules = 2
file_default_policy = accept
file_default_filename = unnamed.file
# Policy num. 1
# Delete obviously executable attachments. This list is VERY
# incomplete! This is a perl regular expression, see "man
# perlre" for info. The (?i) prefix makes the regexp case
# insensitive.
#
# There is only one policy, since we aren't using an external
# scanner.
#
file_list_1 = (?i)\.(pif|com|cmd|bat)$
file_list_1_policy = drop
file_list_1_scanner = 0
# Policy num. 2
# Scan all files for Viruses, using clamscan
# Always define FOUR potential policies, which depend on the
# exit code returned by the scanner. Which code means what is
# defined in the scanner line, which must contain THREE entries.
# The fourth policy is used for "anything else".
#
# "accept" if the file is clean (exit status 0)
# "mangle" if the file was dirty, but is now clean (clamav doesn't
# support file desinfection, so we use the fictive exit status 66)
# "drop" if the file is still dirty (exit status 1)
# "save" if clamscan returns some other exit code or an error occurs.
#
file_list_2 = (?i)\.(exe|zip|tar|tgz|tar\.gz|rar|doc|xls|pps|ppt)$
file_list_2_policy = accept:mangle:drop:save
file_list_2_scanner = 0:66:1:/usr/bin/clamscan --recursive --unzip --unrar --tar --tgz %FILENAME
I believe that the syntax of policy 2 needs a little explanation. The first argument (file_list_2) states which files should be processed by this policy. The second (file_list_2_policy) and third (file_list_2_scanner) arguments are interdependent. The second argument specifies what to do with the attachment depending on what the virus scanner exit code is. As you can see, in this configuration, if clamscan returns 0 we accept the attachment; if it returns 66 we will mangle the attachment; if it returns 1 we drop the attachment and it if returns something else we save the attachment in quarantine.
Test sanitizer
I created an email message containing a fake virus signature to test sanitizer. Save this file and pass it through sanitizer using the following command.
sanitizer /etc/sanitizer.conf < fake-email-virus.txt > fake-email-sane.txt
The infected attachment should be replaced by the following text in the sane
version.
NOTE: An attachment was deleted from this part of the message,
because it failed one or more checks by the virus scanning system.
See the attached sanitization log for more details or contact your
system administrator.The removed attachment's name was:
test1.doc
It might be a good idea to contact the sender and warn them that
their system is infected.
If you get similar results, this means that Sanitizer is properly configured. Congratulations! Only one thing left, tell procmail to use sanitizer.
Configuring procmail to use sanitizer
Add this on the top of your .procmailrc file.
:0fw: | /usr/bin/sanitizer /etc/sanitizer.conf
Since it is pretty short, let me explain what it does.
The first line. The :0 marks the beginning of a new rule. The f means that this rule is a filter. The w tells procmail to wait for sanitizer to finish. The last colon tells procmail to use a lockfile to insure that only one message will be processed at a time. This is important to use a lockfile because otherwise, if you were to receive a batch of several emails at once, procmail would process all these emails in parallel and effectively making a Denial of Service Attack on the system. Believe me, I learned that the hard way! ;-)
The second line is more simple, the pipe (|) means that the message should be directed to the standard input of sanitizer. Then we have the path to sanitizer and to its configuration.
That's it, you now have simple virus scanner attached to your inbox. You only need to test it to be sure that it works properly.
Test the whole thing
To test your new configuration, you fire up your favorite mailer program and send yourself three emails: one containing only text (no attachment), one containing a non-infected attachment and one containing one of the clamav-testfiles as attachment. Make sure that you receive these emails and that they are modified according to your sanitizer configuration.
Posted by gfk at novembre 9, 2004 7:25 PM
Comments
Post a comment
Thanks for signing in, . Now you can comment. (sign out)
(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)