Linux/clamavでウィルス対策

clamav の導入(2018-10-06)


フリーのウィルス対策ソフトは色々あると思いますが、
今回インストールしてみるのは clamav です。


メールサーバ用のCentOS、作業端末用のLubuntuにそれぞれ入れたので、
少し記述がごっちゃになっています。

はじめに

ウィルス対策ソフトのイメージって、市販のやつの感覚になってしまうので
(ぜんぶ自動でやってくれる、という先入観が強いのですが)
まず以下が必要な雰囲気でした

  • そもそもなにをインストールするのか調べる
  • インストール後、configは一通り眺める

たとえば、
本体になる clamav に加えて、
コマンドではなくGUIで動かすなら clamtk
リアルタイム検索なら clamd(clamav-daemon)
メールも検証するなら clamav-milter など
といった感じで、別途入れていかなければ「市販のやつ」っぽく動きません

なにを入れるかは、目的とディストリビューションに合わせて
https://www.clamav.net/downloads
の説明を読むと、分かったり分からなかったりします。*1

そして、設定の例として、
オンアクセススキャン(=リアルタイム検索)の場合だと、
config で ScanOnAccess true に変えて(デフォルトはoff?)
検索対象のディレクトリも指定して、
必要なら「User clamav」の部分もrootとかに変えて...
...色々変えるので、
configファイルのコメント部分、あるいは man clamd.conf
の説明で全体像を見てみたほうが良さげです。*2

全体像を見てみたほうが、というのは、
clamavのバージョンによってconfigパラメータの増減やデフォルト値の変更があるようなので、
それが死活問題にならないといいな、と思いまして。
メールが送受信できない、なら設定の異常に気がつくかもしれませんが、
ウィルスが検出できない、って気がつけ無いですからね...

インストール

以下、clamav-0.100.1 版をインストールした内容です。

私のCentOS 7 の場合は yum を使えるので(以下、rootで実行)

# yum install clamav

Ubuntuだと(https://clamav.net/downloads に詳しく書いてあるのですが)

# apt-get install clamav

また、(GUI環境で)Lubuntu のパッケージマネージャを使って「検索」して
「clamtk」を探してインストールすれば、
依存するcalmav本体と、GUIで管理できる calmTKの双方を入れることができると思います。
apt コマンドでも依存関係はある程度かってに解決してインストールしてくれます。

...ですが、前述の通り、これだけでは色々足りません。
もろもろのオプションを環境に合わせて追加で入れましょう。

そもそも、この時点で何が入っているか良くわからないので、
findコマンドで全検索をかけてみたのですが、
(コマンド名、コンフィグ名が分かれば man で調べることができたり、できなかったりするので)

# find /etc -name "*clam*"
# find /usr -name "*clam*"

なんとなく、cronの有無や、
手動スキャン(clamscan)とデータ更新(freshclam)はできそう、
デーモンである clamd がまだ入っていないことが分かりました。
(clamd に関しては後述)

そんなわけで、
データベース更新に使うコマンドの設定「/etc/freshclam.conf」を更新します。
とりあえず、

UpdateLogFile、LogTime、LogRotate、を有効にして、
DatabaseOwner を rootに変えて、
DatabaseMirror のドメインをjp に(db.XY.clamav.net→ db.jp.clamav.net)

...ですかね、やりながら見直す予定です
(このあとに、clamd導入したときに NotifyClamd も更新、とか)
あと、
「/etc/sysconfig/freshclam」
「/etc/cron.d/clamav-update」
も環境・バージョン次第で更新が必要ですが、
今回の私の環境はそのままで様子見できそうな内容でした。

ここでは2点だけメモしておきますが、

SafeBrowsing というheuristic phishing detectionを提供する機能もあるようです。
(私のPC環境は基本オフラインなので、オフのままですが
 it's mandatory to run freshclam at least every 30 minutes.
 すくなくとも30分毎に更新して使ってね、とコメントに書いてありました)
フィッシング対策とかまでやってくれるのは面白いですね。

それから、
DatabaseMirrorについては、clamtkで(GUIで)更新している場合も
freshclam.conf を直接見て確認したほうが良いかもしれません。
私の環境でデフォルト値が db.local.clamav.net になっていて
ずっと接続エラーになっていましたので。
(ERROR: Can't get information about db.local.clamav.net: Name or service not known
 つまり local を国のドメイン(jp)に直す必要がありました)

さておき、configの設定が終わったら早速データを更新です。

# freshclam

これで更新してみて、それっぽい更新完了ログが出るのを確認しましょう。

デーモン(clamd)のインストール

オンアクセススキャンやら、clamav-milter やらを使うのに clamd が必要になります。

うちの CentOS 7 では

# yum install clamd

コンフィグは /etc/clamd.d/scan.conf ができました。

Lubuntu 16.04 では、clamav-daemon をパッケージマネージャでインストール。
コンフィグは /etc/clamav/clamd.conf ができました。

これは、かなり混乱しました。
clamd なのか、clamav-daemon なのか、clamav-server なのか...
環境とバージョンで名前が変わるようなのでご注意を。
(私の場合は、Web検索した以外に、yum search や find コマンドで
 どの名称が該当するのか探した感じでした)

Lubuntu は後述するとして(オンアクセススキャンの話で)
CentOS の /etc/clamd.d/scan.conf を更新して、clamav-milter に備えます。

# Example ←この行はコメントアウトする!
LogFile、LogTime、LogRotate、を有効にする
LocalSocket を有効にする

...だけ変更して、とりあえず動かしてみます。
先程の /etc/freshclam.conf の NotifyClamd も変えました。
あと、
ログファイルは、たぶん /var/log に権限がないので、最初に手動で作らないといけないかもしれません。
あるいは単純に書込権限が無いだけなら chmod 等で権限付与しても良いかと(chmod 660 とか)。

clamd[3565]: ERROR: Can't initialize the internal logger
clamd[3565]: ERROR: Can't open /var/log/clamd.scan in append mode (check permissions!).
# touch /var/log/clamd.scan
# chown clamscan:clamscan  /var/log/clamd.scan
(ユーザは clamd の起動ユーザに合わせる
 他のユーザにもrwできるようにグループ追加(gpasswd -a)する例は後述)

起動方法ですが、
(やっぱりファイル名がよくわからないので)「find /usr -name "clamd*" 」で探すと、
CentOS 7 だと clamd@scan.service というファイルができていました。
(Lubuntu 16.04だと clamav-daemon でした)
systemctl で有効にして開始します。

# systemctl enable clamd@scan
# systemctl start clamd@scan

無事動きました。
(嘘。ほんとうは、一旦 Out of Memory になったので、それは後述)
これで次は、 milter と連携します。

Postfix と clamav-milter

CentOS 7 の postfix と clamav を連携させて
メール送受信時のウィルス検索を試みます。

まずはインストールから。

# yum install clamav-milter

あと、リブート時に起動もするようにします。

# systemctl enable clamav-milter
# systemctl start  clamav-milter
あるいは
# chkconfig clamav-milter on
# chkconfig clamav-milter start

一部、必要な(mandatoryな)パラメータが未設定だとエラーになります。
以下がそのエラーの例で、Example行のコメントアウト漏れっぽいです。

ERROR: Please edit the example config file /etc/mail/clamav-milter.conf
/usr/sbin/clamav-milter: cannot parse config file /etc/mail/clamav-milter.conf

ちなみに、
「clamav-milter-systemd」なんて素敵なものがあるじゃない!と思ったら、
タイミングが悪くバグがあるようで (2018.9現在)
「yum info clamav-milter-systemd」したら
「 (#1583599). you may remove this package now」なんて注釈が付いていました。
この注釈は他の設定ファイルにも入っていて(例えばclamav-scanner-systemd)、
バグ(1583599)らしいです。

/etc/mail/clamav-milter.conf を更新します。

# Example ←この行はコメントアウトして無効にする
 
MilterSocket /run/clamav-milter/clamav-milter.socket
# 同グループからの書込を許可し、あとで postfixをグループ追加する
MilterSocketMode 660
ClamdSocket unix:/clamdのSocketの設定に合わせる
 
AddHeader Add
 
# ログは、とりあえずsyslogに出力してみて、後日検討予定
LogSyslog yes

コメント欄や manに書いてあるのですが、うちはDKIMありなので AddHeaderは注意が必要です。
(DKIMについては、Linux/opendkim のインストールを参照。
 DKIMってメール全体からハッシュ値を取るから、
 置き換え(Replace)が発生するとハッシュ値が一致しなくなるっぽい)
以下が「man clamav-milter.conf」の説明からの抜粋です。

Note that while
"Replace" can potentially break DKIM signatures,
"Add" may confuse procmail and similar filters.

そして postfixから clamav-milterへアクセスできるように MilterSocketを設定する必要があります。
以下は失敗した場合のログの例ですが、

postfix/cleanup[xx]: warning:
connect to Milter service unix:/run/clamav-milter/clamav-milter.socket: Permission denied

前述の通り、「MilterSocketMode 660」には変えたのですが、
clamav-milter.socket のユーザ/グループが(ls -l で確認したら)clamilt/clamilt だったので、
postfix も、このグループに加えてしまいます。

# gpasswd -a postfix clamilt

そして、とりあえず起動

# systemctl enable clamav-milter
# systemctl start clamav-milter

無事起動できそうなら、postfix を設定します。/etc/main.cf で

smtpd_milters = unix:/run/clamav-milter/clamav-milter.socket
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

ちなみに私の環境は既にsmtpd_milters を使っているので、スペース区切りで他の設定に追加になります。
もし、これが初回導入なら milter周りの install 作業が発生するかもしれません。
そして、「service postfix restart」とか reload とかで再起動します。

試しにテスト用のウィルス(作り方は後述)をメールに添付して送ってみると
postfix のログ(/var/log/maillog)に

(改行しましたが、ほんとうは一行です)
postfix/cleanup[xx]: xxx: milter-hold:
END-OF-MESSAGE from xx.co.jp[xx.xx.xx.xx]:
milter triggers HOLD action; from=(以下略)

なるほど、デフォルト設定(Quarantine)だとHOLD されてメールが配送保留になるようです。
「postqueue -p」で holdされたメール一覧が見られるので、
「postcat -q ID名」とかで
メールの中身見ると、先程送った試験用のメールでした。
ひとまず、これでメールのウィルス検知に成功しました!

ちなみに、
検出時の挙動を Quarantine からReject へ変えれば
善意の送信者へ異常(5xxエラー)を応答通知してあげられるので親切ですが、
悪意の攻撃者へ戦果(ウィルス送付の可否と次の対策)を教えることにもなるので、
私はまずは応答なし(Quarantine か Blackhole)で様子を見ようと思います。

あとメモとして、holdされたメールは
/var/spool/postfix/hold/ に置いてあるメールですが、
これは clamav に限らず、別件でholdされたものも全て含むので、いきなり消さないように。
消すときは
「postsuper -d ID名」、全部いくなら ALL を指定。

オンアクセススキャン

Lubuntu 16.04 環境の clamav に、リアルタイムで検出する機能を付けます。
(clamd のインストールは前述の内容を参照)

インストールの後で、
clamd.conf (CentOS 7 の場合は scan.conf) に
ひとまずは以下を設定してみました。

# ユーザを clamav から root へ変更して、Socketもそれに合わせる
User root
LocalSocketGroup root
# 検索を true にして、それに合わせて設定を追加する
ScanOnAccess true
OnAccessMountPath 検索対象にするマウントポイント
OnAccessIncludePath 検索対象にするPATH
OnAccessMaxFileSize 適当なサイズに増やすor減らす
LogFile 任意のログファイル

ここでは Userを root に変えてオンアクセススキャンに備えましたが、
ここは自環境でどう使うかにあわせる必要があると思います。
場合によっては、オンアクセススキャンを止めることも選択肢に。*3

そして起動 (ここも、CentOS 7 の場合は clamd@scan)

# service clamav-daemon start
あるいは
# systemctl start clamav-daemon

起動の結果はLogFile に出力されるのですが、

ERROR: Failed to change socket ownership to group clamav

上記のエラーになってしまった場合は
Userに合わせて LocalSocketGroup、LocalSocketMode などの権限が足りてない可能性があります。
それから、

ERROR: ScanOnAccess: fanotify_init failed: Operation not permitted
ScanOnAccess: clamd must be started by root

このエラー、権限が色々足りてないわけですが、既にUser root に変えている場合も出るなら、
AppArmor(=セキュリティの何か)の可能性があります。

$ aa-enabled
Yes (←うちのLubuntu環境では、有効になっているらしい)
$ sudo aa-status
(これで、許可・拒否対象になっているコマンドを確認します)

自分の環境では、clamd が enfoced になっていました。
AppAomorの設定を変えようと思ったのですが、
aa-complain コマンドが無いので「apparmor-utils」を追加インストールします。
その上で、

$ sudo aa-complain clamd
$ sudo aa-status
(モードが complain に変わったことを確認)
$ service clamav-daemon restart
(ログを見て、今度はエラーが無いことを確認)

これで起動できたら、試しに試験用のウィルスファイルを取得してみましょう。
検知後にはログが出力されます...ログ出力だけ、なの?

※本当は画面に「検知しました」的なメッセージを出したかったのですが
 私の環境では上手くいきませんでした(後述の「VirusEvent が動かない」件を参照)


動いているのか、確認する方法(試験用のウィルスファイル)

Webで「試験用のウィルスファイル」みたいに検索すると、
「EICARテストファイル」がヒットすると思うので、
これを本家または、信頼できそうなサイト経由でダウンロードしましょう。
ただのテキスト文字列なので、自分で作成&保存でも良さそうです。

このファイルをスキャンすれば、ウィルスを検知した状態になるはずです。

※会社でダウンロードするときは要注意!!

というのは、試験用の「ウィルス・マルウェア」なので
対策ソフトでバッチリ「検知」されて、会社によっては、
履歴に残ったりアラートが飛んだり、
社内の誰かの手間を増やしたり怒られたりすることになるかもしれません。

オンアクセススキャンでVirusEvent が動かない?

VirusEventで、ウィルス検出時の挙動を指定できるのですが
(というより、自分で作らないと検出時のメッセージ表示とかは特にないわけですが)
Webで色々探したところ、この VirusEventが、
もしかしたら 0.100.1版だと動かない(コメントアウトされてる?)という話を見つけました。
ソースで言えば、 clamd/onaccess_fan.c に
virusaction関数をコメントアウトしている箇所があります。
(deadlock とか memory consumptionの可能性があるからコメントアウトしたって書いてありますね)

試しに 0.99版にダウングレードしてから、オンアクセススキャンを試すと、
同じ clamd.conf で VirusEvent が難なく動いてしまったので、
少なくとも私の環境だと 0.100.1 版では動かない(私の conf 設定誤りではない [smile]
と考えても良さげ、です。
(virusaction関数を呼ぶ箇所は1つではないので、環境にもよると思います)

以下は、
興味半分で、古いバージョンに戻してみるメモです。
(Lubuntu 16.04 で実施)

(もし、パッケージ名がわからない場合は、先にキーワードで検索してみる)
$sudo apt-cache search clamav
 
(使えそうなバージョンを調べる)
$ sudo apt-cache policy clamav-daemon
あるいは
$ sudo apt-cache showpkg clamav-daemon
など
 
(結果、どうやら 0.99 なら入れられそうなので、ダウングレードを試みる。
  ダウングレード中に、clamd.conf をどうするか聞いてきたりしましたので、
  あらかじめ confのバックアップを取っておいても良いかもしれません)
 
$ sudo apt-get install clamav-daemon=0.99+dfsg-1ubuntu1 clamav-base=0.99+dfsg-1ubuntu1 clamav-freshclam=0.99+dfsg-1ubuntu1
(自動で生成された clamd.conf に以下を実行するように書いてあったので、実行)
$ sudo dpkg-reconfigure clamav-daemon
 
(あとは OS ごと再起動しました。
  もし、ダウングレード後に自動でアップグレードされると困るなら
  apt-mark hold <package-name> でホールドしておくと良いらしい)

前述の通り、私は結果に満足?したので、バージョンは最新に戻してます。
VirusEventで通知メッセージ出したかったんですけど、
別の方法を考えます。

Out of memory な話

これはCentOS 7のsyslogの内容ですが、clamd起動直後に失敗している件です。
数字の部分はマスク(xx)してます。

kernel: Out of memory: Kill process xxxx (clamd) score xxx or sacrifice child
kernel: Killed process xxxx (clamd) total-vm:xxxxkB, anon-rss:xxxxkB, file-rss:xxxkB, shmem-rss:0kB

どうやらメモリが足りないから clamdを犠牲(sacrifice)にしたと言っていて、
その直後にclamd が再起動していました。

最初、「systemctl start clamd@scan」の後に
clamdの起動に失敗しましたって表示が出ているのに、clamdプロセスは動いていたので混乱しました。
で、(scan.conf がLogSyslog yesの状態で)前後の syslogから
clamd の行を落ち着いて見れば、再起動できているログが残っていました。
再々起動に挑戦したらたまたま上手くいったのかもしれません。

とはいえ、メモリをそんなに食うなら問題なので
「top」コマンドやら、
「ps -eo argc,%mem | grep clam」やら
「pmap -x プロセスID」やらでclamdのメモリ使用量を確認して、
一応、大丈夫でしたが...
他のプロセスと比較すると、ぶっちぎりでメモリを食っていることが分かりました。

その後しばらく様子を見た結果、
やはり、うちの環境だとリソース不足のようで、
しばらく放置すると clamd は自主閉店していました。
(定期的な freshclamによる最新化の際に、clamdが再開できなくなったらしい)

環境に合わせて、clamd失敗時の動作・通知をどうするのか計画した方が良いですね。
(例えば、clamdが止まる→ clamav-milterも黙る→ メールが受けられない、
 のようにclamavと連携したものが止まると困るので)

余談

導入したタイミングが悪かったのか、スリリングな内容になりました。
というのも、前述した
「1583599」という clamavのバグを踏んだ人は大変な目にあっているらしく?
「VirusEvent」も 0.100.1版だと動かない?
という感じで、ちょうど厄介な時にインストールしてしまったようです。

さておき、

Linuxでウィルス対策ソフトが、少ないというか、
個人用というよりは企業向け・サーバー向け(=値段が高い)になってしまう印象が有ります。
個人で使うノートPCやら、個人的なWebサイトに、
エンタープライズ用のウィルス対策ソフトはなかなか敷居が高いです。

もちろん企業で使うときは、それらを買った方が安心かと。
機能やサポート面もありますが、
毎日の運用・保守を考えて「統合管理」も含めてのパッケージを買う、とか。
(例えば、そもそも会社の各PCへ対策ソフトがちゃんと適用されているか調べたり、
 諸々の作業を自力でやるよりも買ってシステム化した方が工数的には安くつくので)

会社とかではなく、自分用の環境なら、
そもそも、
ウィルス対策ソフトを入れていれば安心、という訳でもなく、
ゼロデイ攻撃とか(対策が終わってない、発見されていない脆弱性で攻撃される)
高度標的型攻撃とか(もう入り口で防ぐのは不可能なので、感染後の対策も大切)
とかもあるので、
ウィルス対策ソフトは保険程度に考えて、色々自分で気をつけることには変わりない、
...と考えたほうが精神衛生上良い、心が穏やかになれる気がします。
(過度な期待を寄せて、自分の設定ミスで動作せずに、悶絶するよりは)

それにしても、
同じLinuxベース(?)のAndroidで、各社がウィルス対策ソフト出しているのだから、
もっとLinuxのウィルス対策ソフトも出ると嬉しいですね〜*4


*1 パッケージ名を知る参考にはなりました、が、clamd 関連の話が分からなくて、結局 findコマンドと manコマンドで探し回りました。
*2 市販のやつでも、特に会社・法人向け(えんたーぷらいず)のウィルス対策ソフトだと、結局一つ一つのconfigは設定するというか、設定次第で便利になったり無意味になったりしますけどね。
*3 仕事で使ったのは別のウィルス対策ソフトですが、対策ソフトのスキャンによってファイルがロックして、システムがダウンしたという事例もあったので、単純に root のような強い権限を与えれば良いとも限りません。
*4 最近は有料のウィルス対策ソフトって、スマートフォンとPCを合わせて3台まで〇〇円みたいな売り方ですけど、そこにLinuxも加えてほしいのです。