Help us understand the problem. What is going on with this article?

[改訂版]vulsを使って脆弱性の自動スキャンを実現する

More than 3 years have passed since last update.

vulsは脆弱性確認を楽にしてくれる可能性を秘めた、サーバー運用者にとって期待のツールです。

前回書いた記事に開発者の @kotakanbe@github さんから有益な情報を頂いたのと、その後有益な記事を参考にしたのとで、大幅に文章を修正しました。 あまりに更新量が多かった (=簡略化できた)ので、別記事としています。

具体的には

  • go-cve-dictionaryのdaemon化が不要だった ため、手順を省略しました。
  • 日本語脆弱性辞書を扱うようにしました。
  • 上記変更に伴い、実行例や実行コマンド例も変えました。

なお、導入手順は基本的にオフィシャルに従えば良いのですが、AWSベースで書かれています。本記事はオンプレ用に端折った手順のメモです。

以下、環境はCentOS7で、2016/06/14に実施した手順です。
本手順で入るgo-cve-dictionaryおよびvulsのバージョンは以下です。

$ go-cve-dictionary -v
go-cve-dictionary 0.1.1

$ vuls -v
vuls 0.1.4

前回の記事で作ったサーバーで入れ直しをしているため、多少手順の記載漏れをしているかもしれません。

事前準備

ここでの作業はCentOS7上で、全てrootユーザーを想定しています。

Go言語環境の構築

事前に必要なパッケージをインストールします。
goはtarでダウンロードするので、ちょっとめんどくさいですね。

$ yum -y install sqlite git gcc
$ wget https://storage.googleapis.com/golang/go1.6.2.linux-amd64.tar.gz
$ tar -C /usr/local -xzf go1.6.linux-amd64.tar.gz

/etc/profile.d/goenv.shを作成してこのように記載します。

/etc/profile.d/goenv.sh
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

一回ログアウトして再度ログインすれば、goenv.shが適用されてgoコマンドが使用できるはずです。

SSH公開鍵認証の設定

vulsはAnsibleやChefのように、公開鍵認証のSSHを使用しているようです。検査対象サーバー(ここではローカルホスト)には事前にSSH周りの設定をしておきましょう。

このあたり、AnsibleやChefなどのSSHユーザー管理の話と同じですので、ここでは割愛します。
私の環境ではAnsibleに使用しているユーザーを使用することにしました。

本手順ではこのユーザーを 「sshuser」 と呼ぶことにします。

なお、以下はSSH公開鍵設定の手順例です。

### 認証用の公開鍵を作る
[[vulsサーバー]]
$ su - sshuser

[sshuser] $ ssh-keygen -t rsa
[sshuser] $ cat ~/.ssh/id_rsa.pub

### この内容を検査対象サーバーのSSHログインユーザーに設定
[[検査対象サーバー]]
[sshuser] $ vim ~/.ssh/authorized_keys
[sshuser] $ chmod 600 ~/.ssh/authorized_keys

sshuserで、SSHで対象サーバーにノーパスで入れることを確認しましょう。

導入手順

ここからの作業は、先ほどのsshuserで作業することを想定しています。

[[vulsサーバー]]
$ su - sshuser

cve-dictionaryの初期構築

go-cve-dictionaryインストール

go-cve-dictionaryをダウンロード&インストールしましょう。結構重たいです。

$ go get github.com/kotakanbe/go-cve-dictionary

### 確認
$ type go-cve-dictionary
go-cve-dictionary is hashed (/home/sshuser/go/bin/go-cve-dictionary)

$ go-cve-dictionary -v
go-cve-dictionary 0.1.1

go-cve-dictionaryがインストールされました。
※ 前回記事と違って、GOPATH(各自のホームディレクトリ以下)に実行ファイルがあれば十分です。

ディレクトリの準備

ログディレクトリおよび辞書ディレクトリを作り、sshuserに書込権限を渡しておきます。
この部分はsudoしないと(root権限を取らないと)、おそらく権限不足で失敗するかと思います。

$ sudo mkdir /var/log/vuls
$ sudo chown sshuser:sshuser /var/log/vuls

$ sudo mkdir -p /var/vuls/dict
$ sudo chown sshuser:sshuser /var/vuls/dict

脆弱性辞書の準備

2002年〜2016年に発生した脆弱性について、辞書を取得します。
数分は時間が掛かるので注意しましょう。

$ for i in {2002..2016}; do go-cve-dictionary fetchnvd -dbpath=/var/vuls/dict/cve.sqlite3 -years $i; done

辞書ディレクトリにsqlite3ファイルができたことを確認します。

$ ls -l /var/vuls/dict/cve.sqlite3
-rw-r--r-- 1 sshuser sshuser 574898176 Jun  1 12:00 cve.sqlite3

日本語の脆弱性情報も追加しておきましょう。 こちらはもっと時間が掛かります。
日本語でなくても良い、という方は、この項目は飛ばしてください。

$ go-cve-dictionary fetchjvn -entire -dbpath=/var/vuls/dict/cve.sqlite3

vulsを準備

vulsを手に入れる・・・のですが、 ここで詰まる可能性がある ので、続く手順を先に眺めてください。

$ go get github.com/future-architect/vuls

CentOSの標準yumリポジトリでは、git-1.X系列しかダウンロード出来ないはずです。
この場合、gitのバージョンが古いためにgo getが詰まってしまいます。

そこでwandiscoのリポジトリからgit-2.xをインストールします。

git-2.xのインストール

本節の作業はrootユーザーで、あるいはsudoで実行してください。

/etc/yum.repos.d/wandisco.repoを作成します。

/etc/yum.repos.d/wandisco.repo
[wandisco-git]
name=WANdisco Distribution of git
baseurl=http://opensource.wandisco.com/centos/7/git/$basearch
enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-WANdisco

gitのアップデート

### GPGキーを取り込み
$ rpm --import http://opensource.wandisco.com/RPM-GPG-KEY-WANdisco
$ yum update git --enablerepo=wandisco-git

### バージョンアップ確認
$ git --version
git version 2.8.0

改めてvulsをインストール

では、改めてvulsをgo getしましょう。
※ sshuserに戻るのを忘れないようにご注意を。

$ go get github.com/future-architect/vuls

### 確認
$ type vuls
vuls is hashed (/home/sshuser/go/bin/vuls)

$ vuls -v
vuls 0.1.4

vulsも入りました。
※ 前回記事と違って、GOPATH(各自のホームディレクトリ以下)に実行ファイルがあれば十分です。

vulsによる脆弱性検査

vulsの使用準備

vuls設定ファイルの作成

先ほど作ったvulsサーバーにてconfig.tomlファイルを作成します。

現在のvulsはカレントディレクトリ以下にあるconfig.tomlファイルを読み、カレントディレクトリ以下に結果を出力するのが基本動作です。-configオプションでconfig.tomlのパスを指定することもできます。
以下は設定毎にディレクトリを作っている例です。

$ mkdir hoge
$ cd hoge
$ vim config.toml

中身はこのように書いていきます。
詳しくはオフィシャルを参照してください。

config.toml
[servers]

[servers.localhost]
host        = "127.0.0.1"
port        = "22"
user        = "sshuser"
keyPath     = "/home/sshuser/.ssh/id_rsa"

脆弱性スキャンの実行

vuls prepare

SSH公開鍵ログイン設定が終わったらvuls prepareを実行します。
これにより、SSHの動作確認ができるとともに、動作に必要なyumプラグインが検査対象サーバーにインストールされます。

$ vuls prepare

INFO[0000] Start Preparing (config: /root/config.toml)
[May 24 12:29:25]  INFO [localhost] Detecting OS...
[May 24 12:29:25]  INFO [localhost] (1/1) Detected localhost: centos 6.4
[May 24 12:29:25]  INFO [localhost] Detecting Container OS...
[May 24 12:29:25]  INFO [localhost] Installing...
[May 24 12:29:25]  INFO [localhost] Ignored: yum-plugin-security already installed
[May 24 12:29:25]  INFO [localhost] Installing yum-plugin-changelog...
[May 24 12:29:29]  INFO [localhost] Installed: yum-plugin-changelog
[May 24 12:29:29]  INFO [localhost] Success

vuls scan

ここまで準備出来れば、脆弱性スキャンが実行できます。
config.tomlに書いたサーバーに対しては一気に実行してしまいます ので、稼働中のホストへのスキャンは気をつけてください。

レポートの出力形式はヘルプを見て、適当なものを選びましょう。

$ cd vulsの設定ファイルを作ったフォルダ

$ vuls scan -cve-dictionary-dbpath=/var/vuls/dict/cve.sqlite3 -report-text
### 日本語でレポートを出力する場合は以下
$ vuls scan -cve-dictionary-dbpath=/var/vuls/dict/cve.sqlite3 -report-text -lang=ja

結果は results/current/ ディレクトリに出力されています。

$ ls -1 results/current/*.txt
all.txt
ホスト名.txt

定期的な実行を考える

定期的な実行をし続けることで、運用をもっと楽したいと思います。

脆弱性情報の定期的な更新

とりあえずcronに仕込んじゃいましょう。
コマンドの中身そのものはそれぞれ簡単なワンライナーで、「過去2年間の最新情報を取得する」+「過去1週間の日本語脆弱性辞書を更新する」というものです。

/etc/cron.d/go-cve-dictionary_update
SHELL=/bin/bash
HOME=/home/sshuser
MAILTO=""

# Update CVE dict
37 05 * * * sshuser ${HOME}/go/bin/go-cve-dictionary fetchnvd -last2y -dbpath=/var/vuls/dict/cve.sqlite3 >/dev/null 2>&1
57 05 * * * sshuser ${HOME}/go/bin/go-cve-dictionary fetchjvn -week -dbpath=/var/vuls/dict/cve.sqlite3 >/dev/null 2>&1

HOME環境変数及び実行ユーザーのsshuserは環境に合わせてください。
また、実行時間は 負荷をかけないように適当に変えてください。

定期的な脆弱性診断

定期的に診断を実行するなら、どうやって通知するのが適切か考える必要があります。
vulsはslackに投げる機能もあるのですが、脆弱性発見時は結構な文章量になることを想定して、メール通知で始めてみることにしました。

メール通知を設定する

Cronで実行するためのconfigファイルを作成します。

$ mkdir /var/vuls/cron/config.toml
$ vim /var/vuls/cron/config.toml

自動実行して負荷をかけても問題ないサーバーをスキャン対象にしておきましょう。

このとき、configファイルの先頭に[mail]ブロックを作成します。
詳しくはオフィシャルの設定を見るとして、こんな感じでローカルのsmtpサーバーを使って送信してしまいます。

/var/vuls/cron/config.toml
[mail]
smtpAddr      = "localhost"
smtpPort      = "25"
from          = "xxxxxx@mailaddress.xxxx"
to            = ["xxxxxx@mailaddress.xxxx"]
subjectPrefix = "[vuls]"

[servers]
### 以下スキャン対象のサーバーの指定

なお、オフィシャルではsmtpPortオプションはintegerに見えるのですが、文字列(ダブルクォートで囲む)じゃないとうまく動作しませんでした。この辺は近々直るはずです。

Cronに設定する

この設定ファイルを使ってvuls scanを実行する設定をCronに仕込みます。

本書の手順では、先ほどのconfigファイルは/var/vuls/cronに置いているので、vulsコマンド実行前にcdしています。コマンド末尾の出力言語部分は好みで選んでください。

/etc/cron.d/go-cve-dictionary_scan
SHELL=/bin/bash
HOME=/home/sshuser
MAILTO=""

# Scan target machines
37 06 * * * sshuser cd /var/vuls/cron && ${HOME}/go/bin/vuls scan -cve-dictionary-dbpath=/var/vuls/dict/cve.sqlite3 -report-text -report-mail -lang=ja >/dev/null 2>&1

これで 毎朝嫌というほど脆弱性通知メールが来ることが期待できます。
# 当たり障りない脆弱性は対応を手抜きしちゃいますよね・・・

こちらも、 HOME環境変数及び実行ユーザーのsshuserは環境に合わせてください ね。

重要な脆弱性だけ知りたい

すべて潰すのがツラい。重要な脆弱性だけ知りたい。
・・・という場合は、-cvss-over=Xというパラメータを付けましょう。

例えば、CVSSスコア7以上だけを通知する場合は以下の様なcron設定になります。

/etc/cron.d/go-cve-dictionary_scan
前略

# Scan target machines
37 06 * * * sshuser cd /var/vuls/cron && ${HOME}/go/bin/vuls scan -cve-dictionary-dbpath=/var/vuls/dict/cve.sqlite3 -report-text -report-mail -lang=ja -cvss-over=7 >/dev/null 2>&1

もっとメール量を減らして差分だけを知りたい

という場合はこちらの記事が参考になります。

最後に

以上で、脆弱性を自動スキャンしてメール通知する仕組みを構築しました。
前回の記事よりはすっきりした手順になっているかな、と思います。

数々の気付きを下記の記事から得ました。良い記事をありがとうございます。

改めて、@kotakanbe@github さん、良いツールをありがとうございます!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした