Ubuntu20.04 で ClamAV を使ってウイルススキャン

# はじめに

Linuxが普及してきたので、ウイルス対策なしのノーガード戦法は怖い。

無料のウイルス対策ソフトのClamAVを入れておこう。

# 環境

動作環境は以下の通り。

```bash:Ubuntu
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
```

```bash:ClamAV
$ clamd --version
ClamAV 0.103.2/26226/Fri Jul  9 20:16:15 2021

$ sudo apt list --installed | grep clam
clamav-base/focal-updates,focal-updates,focal-security,focal-security,now 0.103.2+dfsg-0ubuntu0.20.04.2 all [インストール済み、自動]
clamav-daemon/focal-updates,focal-security,now 0.103.2+dfsg-0ubuntu0.20.04.2 amd64 [インストール済み]
clamav-freshclam/focal-updates,focal-security,now 0.103.2+dfsg-0ubuntu0.20.04.2 amd64 [インストール済み、自動]
clamav/focal-updates,focal-security,now 0.103.2+dfsg-0ubuntu0.20.04.2 amd64 [インストール済み]
clamdscan/focal-updates,focal-security,now 0.103.2+dfsg-0ubuntu0.20.04.2 amd64 [インストール済み、自動]
clamtk/focal,focal,now 6.02-1 all [インストール済み]
libclamav9/focal-updates,focal-security,now 0.103.2+dfsg-0ubuntu0.20.04.2 amd64 [インストール済み、自動]
```

# 手順

## インストール

以下のコマンドでインストール。

```bash
sudo apt install clamav clamav-daemon
```

## サービス起動

### clamavデーモン

まず、clamavデーモンを起動する。

clamavデーモンは、clamdscanコマンドからの指示を受信してマルチスレッドでウイルススキャンをするサービス。

```bash
$ sudo systemctl start clamav-daemon.service 
$ sudo systemctl status clamav-daemon.service 
● clamav-daemon.service - Clam AntiVirus userspace daemon
     Loaded: loaded (/lib/systemd/system/clamav-daemon.service; enabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/clamav-daemon.service.d
             └─extend.conf
     Active: active (running) since Fri 2021-07-09 06:35:27 JST; 1 day 9h ago
       Docs: man:clamd(8)
             man:clamd.conf(5)
             https://www.clamav.net/documents/
   Main PID: 1113 (clamd)
      Tasks: 2 (limit: 38399)
     Memory: 1.1G
     CGroup: /system.slice/clamav-daemon.service
             └─1113 /usr/sbin/clamd --foreground=true
```

### clamavアップデータ 

次に、clamavアップデータを起動する。

これが起動していると、自動的にウイルス定義ファイルを更新してくれる。

```bash
$ sudo systemctl start clamav-freshclam.service 
$ sudo systemctl status clamav-freshclam.service 
● clamav-freshclam.service - ClamAV virus database updater
     Loaded: loaded (/lib/systemd/system/clamav-freshclam.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2021-07-09 06:35:33 JST; 1 day 9h ago
       Docs: man:freshclam(1)
             man:freshclam.conf(5)
             https://www.clamav.net/documents
   Main PID: 1578 (freshclam)
      Tasks: 1 (limit: 38399)
     Memory: 297.4M
     CGroup: /system.slice/clamav-freshclam.service
             └─1578 /usr/bin/freshclam -d --foreground=true
```

## 手動検索

手動で検索してみる。

```bash
sudo clamdscan /path/to/scan/target
```

## 定期自動検索

clamav自体には、定期的に自動検索する機能はない。

cronでclamavを定期的に実行して、定期スキャンを実現する。

ここで、clamavには性質の異なる2つのコマンドが用意されているため、インストールする環境にあったコマンドを利用することをおすすめする。

|コマンド|メリット|デメリット|
|---|---|---|
|clamscan|オプションが豊富<br/>daemon不要|遅い|
|clamdscan|早い<br/>マルチスレッド実行可|オプションが少ない<br/>daemon必要|

### 実行速度

clamdscanは、マルチスレッド実行可。

```bash
  ClamdTOP version 0.103.2   Sat Jul 10 17:27:17 2021
NO CONNTIME LIV IDL QUEUE  MAXQ   MEM ENGINE  DBVER DBTIME        HOST
 1 00:00:07  12   0    50    50 1.27G 0.103.2 26226 2021-07-09T20 local
Details for Clamd version:  ClamAV 0.103.2/26226/Fri Jul  9 20:16:15 2021
Primary threads: live 12 idle  0 max 12                                                                                                                              ┌───────────────────────────────────────┐
 [||||||||||||||||||||||||||||||||||||]                                                                                                                              │Mem:  heap  184M mmap    0M unused   0M│
Queue:    50 items     50 max                                                                                                                                        │Libc: used   19M free  165M total  184M│
 [||||||||||||||||||||||||||||||||||||]                                                                                                                              │Pool: count    1 used 1116M total 1116M│
                                                                                                                                                                     │[||||||||||||||||||||||||||||||||||||] │
                                                                                                                                                                     └───────────────────────────────────────┘
 COMMAND       QUEUEDSINCE    FILE
 FILDES            49.713s    fd[31]
 FILDES             5.343s    fd[22]
 FILDES             5.308s    fd[41]
 FILDES             3.684s    fd[66]
 FILDES             3.108s    fd[19]
 FILDES             1.848s    fd[36]
 FILDES             1.291s    fd[34]
 FILDES             0.016s    fd[38]
 FILDES             0.011s    fd[54]
 FILDES             0.009s    fd[52]
 FILDES             0.000s    fd[57]
 STATS              0.000s    
```

### オプション

clamscanのオプションは数十個。

```bash
$ clamscan --help

                       Clam AntiVirus: Scanner 0.103.2
           By The ClamAV Team: https://www.clamav.net/about.html#credits
           (C) 2021 Cisco Systems, Inc.

    clamscan [options] [file/directory/-]

    --help                -h             Show this help
    --version             -V             Print version number
    --verbose             -v             Be verbose
    --archive-verbose     -a             Show filenames inside scanned archives
    --debug                              Enable libclamav's debug messages
    --quiet                              Only output error messages
    --stdout                             Write to stdout instead of stderr. Does not affect 'debug' messages.
    --no-summary                         Disable summary at end of scanning
    --infected            -i             Only print infected files
    --suppress-ok-results -o             Skip printing OK files
    --bell                               Sound bell on virus detection

    --tempdir=DIRECTORY                  Create temporary files in DIRECTORY
    --leave-temps[=yes/no(*)]            Do not remove temporary files
    --gen-json[=yes/no(*)]               Generate JSON description of scanned file(s). JSON will be printed and also-
                                         dropped to the temp directory if --leave-temps is enabled.
    --database=FILE/DIR   -d FILE/DIR    Load virus database from FILE or load all supported db files from DIR
    --official-db-only[=yes/no(*)]       Only load official signatures
    --log=FILE            -l FILE        Save scan report to FILE
    --recursive[=yes/no(*)]  -r          Scan subdirectories recursively
    --allmatch[=yes/no(*)]   -z          Continue scanning within file after finding a match
    --cross-fs[=yes(*)/no]               Scan files and directories on other filesystems
    --follow-dir-symlinks[=0/1(*)/2]     Follow directory symlinks (0 = never, 1 = direct, 2 = always)
    --follow-file-symlinks[=0/1(*)/2]    Follow file symlinks (0 = never, 1 = direct, 2 = always)
    --file-list=FILE      -f FILE        Scan files from FILE
    --remove[=yes/no(*)]                 Remove infected files. Be careful!
    --move=DIRECTORY                     Move infected files into DIRECTORY
    --copy=DIRECTORY                     Copy infected files into DIRECTORY
    --exclude=REGEX                      Don't scan file names matching REGEX
    --exclude-dir=REGEX                  Don't scan directories matching REGEX
    --include=REGEX                      Only scan file names matching REGEX
    --include-dir=REGEX                  Only scan directories matching REGEX

    --bytecode[=yes(*)/no]               Load bytecode from the database
    --bytecode-unsigned[=yes/no(*)]      Load unsigned bytecode
                                         **Caution**: You should NEVER run bytecode signatures from untrusted sources.
                                         Doing so may result in arbitrary code execution.
    --bytecode-timeout=N                 Set bytecode timeout (in milliseconds)
    --statistics[=none(*)/bytecode/pcre] Collect and print execution statistics
    --detect-pua[=yes/no(*)]             Detect Possibly Unwanted Applications
    --exclude-pua=CAT                    Skip PUA sigs of category CAT
    --include-pua=CAT                    Load PUA sigs of category CAT
    --detect-structured[=yes/no(*)]      Detect structured data (SSN, Credit Card)
    --structured-ssn-format=X            SSN format (0=normal,1=stripped,2=both)
    --structured-ssn-count=N             Min SSN count to generate a detect
    --structured-cc-count=N              Min CC count to generate a detect
    --structured-cc-mode=X               CC mode (0=credit debit and private label, 1=credit cards only
    --scan-mail[=yes(*)/no]              Scan mail files
    --phishing-sigs[=yes(*)/no]          Enable email signature-based phishing detection
    --phishing-scan-urls[=yes(*)/no]     Enable URL signature-based phishing detection
    --heuristic-alerts[=yes(*)/no]       Heuristic alerts
    --heuristic-scan-precedence[=yes/no(*)] Stop scanning as soon as a heuristic match is found
    --normalize[=yes(*)/no]              Normalize html, script, and text files. Use normalize=no for yara compatibility
    --scan-pe[=yes(*)/no]                Scan PE files
    --scan-elf[=yes(*)/no]               Scan ELF files
    --scan-ole2[=yes(*)/no]              Scan OLE2 containers
    --scan-pdf[=yes(*)/no]               Scan PDF files
    --scan-swf[=yes(*)/no]               Scan SWF files
    --scan-html[=yes(*)/no]              Scan HTML files
    --scan-xmldocs[=yes(*)/no]           Scan xml-based document files
    --scan-hwp3[=yes(*)/no]              Scan HWP3 files
    --scan-archive[=yes(*)/no]           Scan archive files (supported by libclamav)
    --alert-broken[=yes/no(*)]           Alert on broken executable files (PE & ELF)
    --alert-broken-media[=yes/no(*)]     Alert on broken graphics files (JPEG, TIFF, PNG, GIF)
    --alert-encrypted[=yes/no(*)]        Alert on encrypted archives and documents
    --alert-encrypted-archive[=yes/no(*)] Alert on encrypted archives
    --alert-encrypted-doc[=yes/no(*)]    Alert on encrypted documents
    --alert-macros[=yes/no(*)]           Alert on OLE2 files containing VBA macros
    --alert-exceeds-max[=yes/no(*)]      Alert on files that exceed max file size, max scan size, or max recursion limit
    --alert-phishing-ssl[=yes/no(*)]     Alert on emails containing SSL mismatches in URLs
    --alert-phishing-cloak[=yes/no(*)]   Alert on emails containing cloaked URLs
    --alert-partition-intersection[=yes/no(*)] Alert on raw DMG image files containing partition intersections
    --nocerts                            Disable authenticode certificate chain verification in PE files
    --dumpcerts                          Dump authenticode certificate chain in PE files

    --max-scantime=#n                    Scan time longer than this will be skipped and assumed clean (milliseconds)
    --max-filesize=#n                    Files larger than this will be skipped and assumed clean
    --max-scansize=#n                    The maximum amount of data to scan for each container file (**)
    --max-files=#n                       The maximum number of files to scan for each container file (**)
    --max-recursion=#n                   Maximum archive recursion level for container file (**)
    --max-dir-recursion=#n               Maximum directory recursion level
    --max-embeddedpe=#n                  Maximum size file to check for embedded PE
    --max-htmlnormalize=#n               Maximum size of HTML file to normalize
    --max-htmlnotags=#n                  Maximum size of normalized HTML file to scan
    --max-scriptnormalize=#n             Maximum size of script file to normalize
    --max-ziptypercg=#n                  Maximum size zip to type reanalyze
    --max-partitions=#n                  Maximum number of partitions in disk image to be scanned
    --max-iconspe=#n                     Maximum number of icons in PE file to be scanned
    --max-rechwp3=#n                     Maximum recursive calls to HWP3 parsing function
    --pcre-match-limit=#n                Maximum calls to the PCRE match function.
    --pcre-recmatch-limit=#n             Maximum recursive calls to the PCRE match function.
    --pcre-max-filesize=#n               Maximum size file to perform PCRE subsig matching.
    --disable-cache                      Disable caching and cache checks for hash sums of scanned files.

Pass in - as the filename for stdin.

(*) Default scan settings
(**) Certain files (e.g. documents, archives, etc.) may in turn contain other
   files inside. The above options ensure safe processing of this kind of data.

```

clamdscanのオプションは、せいぜい10個程度

```bash
$ clamdscan --help

                      Clam AntiVirus: Daemon Client 0.103.2
           By The ClamAV Team: https://www.clamav.net/about.html#credits
           (C) 2021 Cisco Systems, Inc.

    clamdscan [options] [file/directory/-]

    --help              -h             Show this help
    --version           -V             Print version number and exit
    --verbose           -v             Be verbose
    --quiet                            Be quiet, only output error messages
    --stdout                           Write to stdout instead of stderr. Does not affect 'debug' messages.
                                       (this help is always written to stdout)
    --log=FILE          -l FILE        Save scan report in FILE
    --file-list=FILE    -f FILE        Scan files from FILE
    --ping              -p A[:I]       Ping clamd up to [A] times at optional interval [I] until it responds.
    --wait              -w             Wait up to 30 seconds for clamd to start. Optionally use alongside --ping to set attempts [A] and interval [I] to check clamd.
    --remove                           Remove infected files. Be careful!
    --move=DIRECTORY                   Move infected files into DIRECTORY
    --copy=DIRECTORY                   Copy infected files into DIRECTORY
    --config-file=FILE                 Read configuration from FILE.
    --allmatch            -z           Continue scanning within file after finding a match.
    --multiscan           -m           Force MULTISCAN mode
    --infected            -i           Only print infected files
    --no-summary                       Disable summary at end of scanning
    --reload                           Request clamd to reload virus database
    --fdpass                           Pass filedescriptor to clamd (useful if clamd is running as a different user)
    --stream                           Force streaming files to clamd (for debugging and unit testing)
```

### スクリプト作成

次にcronから呼び出すスクリプトを作成する。

#### clamscanを使用する場合

clamscanを使用した例は以下。

```bash:scan.sh
#!/bin/bash

/usr/bin/clamscan \
	--exclude-dir=/path/to/exlude/directories \
	--exclude-dir=/path/to/exlude/directories \
	-i \
	-r $HOME \
	--log="$HOME/.clamtk/history/$(date +\%Y\%m\%d-\%H\%M\%S).log" \
	2>/dev/null
```


#### clamdscanを使用する場合

clamdscanを使用した例は以下。

```bash
mkdir -p $HOME/.clamtk/virus
mkdir -p $HOME/.clamtk/history

find $HOME -type d | xargs clamdscan \
  --infected \
  --multiscan \
  --fdpass \
  --move="$HOME/.clamtk/virus" \
  --log="$HOME/.clamtk/history/$(date +\%Y\%m\%d-\%H\%M\%S).log"
```

ポイントは、 `--multiscan` オプション。

これで、マルチスレッドでスキャンができて早い。

ただし、重い・・・。

### crontabの設定

crontab にスクリプトを設定する。

```bash:crontab
$ crontab -e
$ crontab -l | grep clamscan
0 20 * * * bash /path/to/scan.sh
```