Friday, December 6, 2013

Virus Scanner using ClamAv

Virus Scanner Component

Introduction

As part of any project, we will allow users to upload some documents. We must scan these files for viruses and malware. To that end, we will use ClamAV as our virus scanner. ClamAV has a daemon process that can run on the OS in the background waiting for requests to scan data. We will submit files that we receive from the user to this daemon to scan. Based on the result, we will either reject the file or persist it on our system.

ClamAV

ClamAV is an open-source virus scanner. It provides a daemon process that can be used to scan data. For our purposes, we will set up the ClamAV daemon to listen for requests on a TCP socket. Using our Java API, we will send request to scan data to that socket and inspect the results returned by ClamAV.

Setting up ClamAV on Ubuntu

We will use the default ClamAV that is packaged with Ubuntu. The advantage of this is that it will be easier to update the scanner, than if we built it from source code.

Setting Up ClamAV

To install ClamAV
sudo apt-get install clamav
This will install ClamAV, create a ClamAV user etc. This does not install the daemon process.

Setting Up ClamAV Daemon

 To install the ClamAV Daemon
sudo apt-get install clamav-daemon
This will create the ClamAV Daemon process and start it up.

Updating virus definitions

By default freshclam is installed as a daemon and the default update frequency is 24 times a day. You can update this by modifying the file /etc/clamav/freshclam.conf

Configuring ClamAV Daemon

The default ClamAV Daemon configuration does not create the TCP socket that we need. To set it up, we will need to add the following lines to /etc/clamav/clamd.conf at the end

clamd.conf
# TCP port address.
# Default: no
TCPSocket 3310
 
 
# TCP address.
# By default we bind to INADDR_ANY, probably not wise.
# Enable the following to provide some degree of protection
# from the outside world.
# Default: no
TCPAddr 127.0.0.1
 
 
# Close the connection when the data size limit is exceeded.
# The value should match your MTA's limit for a maximum attachment size.
# Default: 25M
StreamMaxLength 100M

Once this is done, you should restart the clamd service using the following line
sudo service clamav-daemon restart

Java Application Setup

To communicate with the ClamAV daemon, ClamAV defines a protocol. We could write Java code to use that protocol to make our request. Luckily there is a Jenkins plugin that we can leverage that already has a Java API for ClamAV.

Maven Import

Add the following maven import to your project pom file.
Maven Dependency
<dependency>
    <groupId>org.jenkins-ci.plugins</groupId>
    <artifactId>clamav</artifactId>
    <version>0.2.1</version>
</dependency>

Usage

To actually perform a scan on a given set of data, you can use the following snippet of code   

// Create a ClamAvScanned with a given hostname/IPAddress and the port.
// This should match what is put in the /etc/clamav/clamd.conf file.
//
// The third value is the timeout in milliseconds before we give up
// on talking to the ClamAV daemon
// If the Daemon is running on the same machine, you can specify "localhost" as the IP address.
ClamAvScanner scanner = new ClamAvScanner("192.168.23.129", 3310, 5000);
 
// To check whether the scanner is listening at the port, you can "Ping" it
// isAvailable will return true if the server responds to the "Ping"
boolean isAvailable = scanner.ping();
 
 
// In the example, we are passing a ByteArrayInputStream of a String.
//
// You can pass any InputStream that you want. It could be a File,
// a Socket, anything.
// The string passed in this example will return as a virus.
ScanResult result = scanner.scan(new ByteArrayInputStream("X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*".getBytes()));
 
 
// ScanResult.Status is an enum with 3 values:
// PASSED, INFECTED, WARNING
//
// WARNING indicates that an error occurred while trying to scan the file. ScanResult.getMessage() will give you the exception message.
// INFECTED indicates that the file does contain a virus. ScanResult.getMessage() returns the virus' signature.
//
// If the result is PASSED, we sould consider the file safe
if (result.getStatus() == ScanResult.Status.PASSED) {
    System.out.println("No Virus");
} else {
    System.out.println("Possible Virus detected");
}


Setting up ClamAV Daemon on Windows machines for testing

To install the ClamAV daemon follow the instructions on this page:
http://www.andornot.com/blog/post/How-to-set-up-ClamAV-as-a-Windows-Service-to-scan-file-streams-on-demand.aspx