脆弱性検知ツールVulsをZabbixと連携する
はじめに
前回でVulsサーバの構築が完了しました。
Zabbixとの連携
zabbix-sernderのインストール
zabbix-sender
とjq
をインストールします。
$ sudo apt install jq zabbix-sender
vuls_autoscan_for_zabbix
usiusi360さんのGitHubリポジトリから、vuls_autoscan_for_zabbixのシェルスクリプトを取得します。
$ curl -O https://raw.githubusercontent.com/usiusi360/vuls_autoscan_for_zabbix/master/create_config.sh
$ curl -O https://raw.githubusercontent.com/usiusi360/vuls_autoscan_for_zabbix/master/vuls_autoscan_for_zabbix.sh
$ chmod 700 create_config.sh vuls_autoscan_for_zabbix.sh
create_config
Zabbixに登録されているホストを自動で取得してくれて、それらをVulsスキャン対象ホストとして自動でconfig.tomlを作成してくれるシェルスクリプトです。
自分の環境に合わせて編集が必要ですので、まず原本を退避させます。
$ cp create_config.sh create_config.sh.org
create_config.shに自分のZabbixサーバの情報を記載します。
加えて、ここではZabbixAPIのURLをhttps
に変更しました。
$ vi create_config.sh
$ diff create_config.sh create_config.sh.org
3,5c3,5
< ZABBIX_SERVER="{YOUR ZABBIX SERVER}"
< ZABBIX_USER="Admin"
< ZABBIX_PASS="xxxxxxx"
---
> ZABBIX_SERVER="localhost"
> ZABBIX_USER="Admin"
> ZABBIX_PASS="hogehoge"
10c10
< url="https://${ZABBIX_SERVER}/zabbix/api_jsonrpc.php"
---
> url="http://${ZABBIX_SERVER}/zabbix/api_jsonrpc.php"
config.toml.master
config.tomlを生成する元となる、マスターファイルなるものを作成します。
以下の記述があればマスターファイルとして機能します。
$ vi config.toml.master
[default]
port = "22"
user = "locadmin"
KeyPath = "/home/vulsuser/.ssh/xxxxx"
create_config.shを実行
create_config.shを実行すると既存のconfig.tomlが消えるので、実行前に退避しておきます。
$ cp config.toml config.toml.org
create_config.shを実行します。
$ ./create_config.sh
これでZabbixに登録されているホストがconfig.tomlに自動的に記載されます。
(エージェント監視しているものが追加されていることを確認しました。)
作成された内容を確認します。
$ cat config.toml
設定の調整
必要に応じてスラック通知の設定や、対象ホストに個別の鍵やユーザ名を設定します。
個別に指定しなかった項目は[default]
に記載の値が適用されます。
[slack]
hookURL = "https://hooks.slack.com/services/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"
channel = "#vuls"
[default]
port = "22"
user = "locadmin"
KeyPath = "/home/vulsuser/.ssh/xxxxx"
[servers]
[servers.name1]
host = "192.168.1.1"
user = "xxxxx"
[servers.name2]
host = "scanserver1"
keyPath = "/home/vulsuser/.ssh/xxxxx"
[servers.name3]
host = "10.1.1.1"
user = "xxxxx"
~snip~
定期実行
vuls_autoscan_for_zabbixをcronで定期実行します。
月初のサーバチェックで使用するので、毎月1日の午前1時にvuls_autoscan_for_zabbixを実行します。2時にログローテーションも設定しました。
$ crontab -l
~snip~
#vuls autoscan for zabbix
00 1 1 * * /home/vulsuser/vuls_autoscan_for_zabbix.sh > /var/log/vuls/vuls.log 2>&1
#vuls results remove
00 2 1 * * find /home/vulsuser/results/ -mtime +180 -delete > /dev/null 2>&1
vuls_autoscan_for_zabbixの改造
作業当時は、vuls_autoscan_for_zabbix内にあるVulsのコマンド構文が上手く動作しなかったため、少し修正を加えました。例えば次のような箇所です。
+ go-cve-dictionary fetch ${target} ${PROXY} ${years}
- go-cve-dictionary fetch${target} ${PROXY} -years $years
+ goval-dictionary fetch ${target} ${PROXY} ${option}
- goval-dictionary fetch-${target} ${PROXY} ${option}
jqでスキャン結果のjsonを処理する部分も上手く動作しなかったため、機能の追加も兼ねて以下のように自作しました。
- 初回スキャンは全ての脆弱性を、以降は増加分の脆弱性を報告する。
- 以下の内容を報告する。
- CVE ID
- 影響を受けるパッケージ
- CVSS3の最大スコア
- 脆弱性の個数
send_zabbix(){
files="${VULS_LOG}/current/*.json"
for filepath in $files; do
TARGET_NAME=`basename $filepath .json`
echo -n >| /home/vulsuser/results/current/${TARGET_NAME}_cve_list_new
cve_list_new="/home/vulsuser/results/current/${TARGET_NAME}_cve_list_new"
echo -n >| /home/vulsuser/results/current/${TARGET_NAME}_diff_list
diff_list="/home/vulsuser/results/current/${TARGET_NAME}_diff_list"
echo -n >| /home/vulsuser/results/current/${TARGET_NAME}_score
score="/home/vulsuser/results/current/${TARGET_NAME}_score"
echo -n >| zabbix.log
zabbix_log="zabbix.log"
cve_list="/home/vulsuser/results/list/${TARGET_NAME}_cve_list"
if [ ! -e ${cve_list} ]; then
touch ${cve_list}
fi
if [ "${TARGET_NAME}" == "all" ]; then
continue
fi
cat $filepath | jq -r '..|.cveID? | select(.!=null)' | uniq >> $cve_list_new
diff $cve_list_new $cve_list | egrep "^<" | cut -d " " -f 2- >> $diff_list
if [ -s $diff_list ]; then
zabbix_sender -z ${ZABBIX_SERVER} -s ${TARGET_NAME} -k nvd_count -o `grep -c '' $diff_list` >> $zabbix_log 2>&1
zabbix_sender -z ${ZABBIX_SERVER1} -s ${TARGET_NAME} -k nvd_count -o `grep -c '' $diff_list` >> $zabbix_log 2>&1
while read LINE; do
pkg_name=`cat $filepath | jq '..|."'$LINE'"? | select(.!=null)' | jq -r '..|.name? | select(.!=null)' | perl -pe 's/\n/, /g' | perl -pe 's/, $//g'`
cat $filepath | jq '..|."'$LINE'"? | select(.!=null)' | jq -r '..|.cvss3Score? | select(.!=null)' >> $score
echo ${TARGET_NAME} cve_id ${LINE}, Packages: ${pkg_name} | zabbix_sender -z ZABBIX_SERVER -i - >> $zabbix_log 2>&1
done < $diff_list
zabbix_sender -z ${ZABBIX_SERVER} -s ${TARGET_NAME} -k nvd_max -o `cat $score | awk '{if(m<$1) m=$1} END{print m}'` >> $zabbix_log 2>&1
zabbix_sender -z ${ZABBIX_SERVER1} -s ${TARGET_NAME} -k nvd_max -o `cat $score | awk '{if(m<$1) m=$1} END{print m}'` >> $zabbix_log 2>&1
cp $cve_list_new $cve_list
else
zabbix_sender -z ${ZABBIX_SERVER} -s ${TARGET_NAME} -k nvd_count -o 0 >> $zabbix_log 2>&1
zabbix_sender -z ${ZABBIX_SERVER1} -s ${TARGET_NAME} -k nvd_count -o 0 >> $zabbix_log 2>&1
zabbix_sender -z ${ZABBIX_SERVER} -s ${TARGET_NAME} -k nvd_max -o 0 >> $zabbix_log 2>&1
zabbix_sender -z ${ZABBIX_SERVER1} -s ${TARGET_NAME} -k nvd_max -o 0 >> $zabbix_log 2>&1
fi
done
}
また、スキャン結果やvuls_autoscan_for_zabbix実行中のエラーもスラックで通知するように追記しました。
my_logger
はあらかじめvuls_autoscan_for_zabbix内に記載されている関数です。
hook() {
curl -s -S -X POST --data-urlencode "payload={\"channel\": \"${channel}\", \"username\": \"${username}\", \"text\": \"$1\" }" ${hookURL} > /dev/null 2>&1
}
scan(){
echo -n >| vuls_scan.log
scan_log="vuls_scan.log"
vuls scan >> $scan_log
if [ $? -eq 0 ];then
my_logger "[INFO] Scan success."
else
my_logger "[ERROR] Scan fail."
scan_err=`cat $scan_log`
hook "[ERROR] Scan fail. $scan_err"
exit 1
fi
}
report(){
echo -n >| vuls_report.log
report_log="vuls_report.log"
vuls report -format-json >> $report_log
if [ $? -eq 0 ];then
my_logger "[INFO] Scan success."
else
my_logger "[ERROR] Scan fail."
report_err=`cat $report_log`
hook "[ERROR] Scan fail. $report_err"
exit 1
fi
}
これでVulsとZabbixの連携についての手順は終了です。
Discussion