Overview

This week I set up ClamAV on an Ubuntu ec2 instance, with the intention of scanning files remotely from our software. This guide will walk through the setup of ClamAV to run the clamd service on port 3310, and then having a Windows host run a small .py file to scan a file using the clamd service.

Prerequisites

  1. You will need a Linux machine, with SSH access to it, as well as allowing inbound 3310 from the servers you are going to connect from
  2. A Windows machine with python installed

Configuring ClamAV

  1. SSH into your Linux machine and verify it is up to date
sudo apt update
sudo apt upgrade
  1. Install ClamAV and ClamAV Daemon (clamd) and configure the user it will run as
apt-get install -y cargo rustc
groupadd clamav
useradd -g clamav -s /bin/false -c "Clam Antivirus" clamav
sudo apt install clamav clamav-daemon
  1. Edit the clamd.conf file
sudo nano /etc/clamav.clamd.conf
  1. You will want to make several config changes here:

    • LocalSocketGroup clamav
    • User clamav
    • TCPSocket 3310
    • TCPAddr <IP of Linux Machine>
  2. To enable automatic updates, edit the FreshClam configuration file:

sudo nano /etc/clamav/freshclam.conf
  1. Start the clamd service and enable it to start at boot
sudo systemctl restart clamav-daemon
sudo systemctl enable clamav-daemon

Testing Windows Connection

  1. Now that you have your clamAV server running, you should be able to connect to it on port 3310 from your Windows machine, assuming that your network allows it. To test this, from your Windows Machine, run the following:
Test-NetConnection -ComputerName <linux_server_ip> -Port 3310
  1. Install the pyclam library on your windows machine

pip install pyclamd

  1. Create the remote_scan.py file on your computer
import argparse
import pyclamd
import os
import time

clamav_server_ip = '172.16.63.55'  # Replace with your Linux server's IP address

def scan_file_remote(file_path):
    # Convert Windows-style path to Linux-style path
    linux_file_path = file_path.replace('\\', '/')

    try:
        cd = pyclamd.ClamdNetworkSocket(clamav_server_ip, 3310)
        cd.ping()  # Test the connection

        if cd.version() == 'ClamAV/1.0':
            cd.reload()

        scan_results = cd.scan_stream(open(file_path, 'rb'))

        attempts = 0
        while scan_results is None and attempts < 5:
            time.sleep(1)
            scan_results = cd.scan_stream(open(file_path, 'rb'))
            attempts += 1

        if scan_results is not None:
            if 'FOUND' in scan_results:
                print('File is infected:', scan_results['FOUND'])
            else:
                print('File is clean.')
        else:
            print('No scan results received after multiple attempts.')

    except pyclamd.ConnectionError as conn_ex:
        print(f'Connection error: {conn_ex}')
    except Exception as ex:
        print(f'An unexpected error occurred: {ex}')

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Remote ClamAV File Scanner')
    parser.add_argument('file_path', help='Path of the file to scan')
    args = parser.parse_args()

    # Convert the local file path to an absolute path
    args.file_path = os.path.abspath(args.file_path)

    scan_file_remote(args.file_path)
  1. Test using a test file

python remote_scan.py "C:\temp\test.txt"