CVE情報調査 Vuls編 ＠2024春

# そういえば

昔の自分の記事を読んでいて、本丸のVulsの使い方まとめてなかったことを思い出しました。
久しくVulsを使っていないこともあり、使い方も結構変わってるかも。
と、いうことで、改めて整理していきます。

- [この１年でなにか変わった](#この１年でなにか変わった)
- [Vulsの選択肢](#Vulsの選択肢)
- [Vulsを使ってみる](#Vulsを使ってみる)
- [まとめ](#まとめ)

# この１年でなにか変わった？

今回新たに使っていて、ここってこんな仕様だったんだっけかな、、、と思う箇所がいくつかあったのですが、GitのトップページのREADMEの差分を見た感じ、大きな変更はありませんでした。
自分の用途では使わないからガン無視したんだっけかな、、、
まぁ、いいか。

# Vulsの選択肢

構成や導入方法、スキャン方法など、選択肢が色々あるので、使うたびに前どうしたっけか、、になります。
ざっくりプロコンをメモっておきます。

## 機能の構成

https://vuls.io/docs/en/architecture-remote-local.html

まず、機能としてざっくり分けて書くと、以下、、でしょうか。

- 0 調査対象, Scan Targer Server
- 1 調査対象の構成を調べる機能, Vulsの中の黄色いScan
- 2 公開情報（脆弱性情報）を集めておく機能, go-cve-dictionaru, goval-dictionary
- 3 1と3のデータを照合して、調査対象に存在する脆弱性情報を一覧化してレポートする機能, Vulsの中の黄色いReport

これらのくくり方がいくつかある、と。
また、１~３について、コマンドラインからワンショットで駆動する方法だけでなく、Webサーバとして起動しておいてAPIで命令受け取って駆動する方法があるようです。
後者は、全然使ったことないんですよね、、とりあえず今回も封印しておきます。

- 4 1-4のインストールや処理をまとめてキックしてくれる便利スクリプト群, Vulsctl

最初、Vulsctlをサーバ的な機能と勘違いして、アーキテクチャ図に登場しないなぁ、、と混乱してました。。。
機能というよりは、単純な、便利スクリプト集としてみれば良さそうです。

### Remote Scan Mode

0, 1+2+3の構成ですね。

### One-line scan mode

0+1相当を手動実施, 2+3。
ただし、3についてはデータを0+1から受け取る都合で、Webサーバモードで稼働している必要あり。

### Local Scan Mode

0+1+2+3,,,だと思う。
sshを使わないらしい。
設定ファイル上はportの指定の仕方が違うのだけど、そこで首振りしているのかな。。

### プロコン

私の場合、大体のケースで、”0を汚さない”が最優先になります。
その時点でLocalは採用外。

One-lineは、うつコマンドが結構長くてしんどいのと、サーバモードで稼働する関係で0 > 3方向の通信を通してやらないといけないので、FWに穴を開けるのがちょっときもいかな。。

ということで、Remote構成をだいたい使うことになると思います。

## インストール方法

dockerコンテナとして展開する方法と、ホストにインストールする方法（on HostOS)があります。

で、on HostOSの方はさらに、Vulsctlのinstall.shを使う方法、機能を１つ１つ手でコンパイルしていく方法（と言っても機能ごとにインストールスクリプト用意してくれてますが）、パッケージ使う方法（ずっと未実装）、Ansible使う方法（これも実質中身は空っぽ）、awless使う方法（こっちは中身あり）に分かれる感じです。


### docker型

明にインストールという手順はない。dockerが駆動すようにしておけばよい。
Vulsctlにある各スクリプトを実行すると、実行時に必要なコンテナをダウンロードしてきて、実行する。

Tutorialの手順は、基本こちらの構成を使う前提で記載されている。
vulsctlを見ると、docker用のほうが量が多い。
tui.shのようにvulsコマンドをラッピングしてるだけのものや、vulsrepoのようにon HostOSが持ってない機能もある。

### on HostOS型

Vulsctlにある、vulsctl/install-host/install.shを実行すると、必要パッケージやコードをダウンロードして、ホスト上でコンパイルして、実行ファイルを/user/local/binに配置する。
便利スクリプトは配置しないので、git cloneしてきたVulsctlはインストール後も必要。

ちなみにサイトの手順書だと、Vulsctlをgit cloneして、vulsctl/install_hostにcdするという手順が抜けています。
んなもんわかるだろ、と言われればわかるのですが、、目次から対象ページ直接開いた際はガッツリ混乱して、install.shだけ個別でwgetして実行して、次のupdate-all.shで内部で使用しているスクリプトがないぞ、、となってました。。。

### プロコン

調査する側のOSも極力汚したくはない（不要なソフトは入れたくない）のですが、、
docker導入 VS gcc諸々の導入。
どっちもどっちだなぁ、、

視点を変えて、Vuls自体を長期利用することを考えると、一旦手元にダウンロードしたコードを使い続けられるon HostOSのほうが良い気がしましたが、、
詳細は別途まとめておこうかと思いますが、結局都度アップデート追従する以外に方法なさそうですので、どっちでもいいですね。

機能面でいうとdocker構成側にはon HostOS側にはない機能があるっぽいですが、自分の用途的に使うかな、、

結論としては、微妙ですが、docker型を使うことにしようと思います。
今のところは。

# Vulsを使ってみる

基本的に公式サイトの内容に従うのですが、けっつまづいた箇所が結構あるので、メモっておきます。

## スキャンの前に

まず、update.shなどを使って、ソースから公開情報をかき集めてきます。
CVE情報はVulsにはついてこないので。
集めてきた情報は、update.shなどを実行したディレクトリ直下に、sqlite3ファイルとして配置されます。
手順書通り実行すると、便利スクリプトが配置されているディレクトリの直下にこれらのファイルがポコポコっとできあがります。
ちょっと気持ち悪さがなくもないですが、、まぁ、気になったら後日頭の整理します。

また、これらの情報は日々ガンガン更新されるので、スキャン前に毎回更新するのを忘れないように。

## パッケージベースの調査とCPEベースの調査

マニュアルのとおり、、なのですが、今回ここからして全く覚えてなかったので、次回に向けてメモっておきます。

### パッケージベースのスキャン

検査対象のサーバに、鍵認証方式でSSHして、パッケージ情報を引っこ抜いてくる方法です。
設定ファイルにIP、ポート、ログインに使うSSH鍵を指定します。
https://vuls.io/docs/en/tutorial-vulsctl-docker.html#creating-configtoml

### CPEベース

CPEのリストを、config.tomlにベタ書きします。
https://vuls.io/docs/en/tutorial-vulsctl-docker.html#cpe-scan

## docker構成の場合、「コンテナから見た」設定を書く

主にcomfig.tomlの部分の話になります。

keyPathは、自ユーザのホームディレクトリ配下の.sshを、コンテナ内の/root/.sshにマウントします。
設定ファイル見て、「自分はuserアカウントで実行するから/home/userに変えなきゃ」とかはいらないわけですね。。

また、hostも、コンテナから見たものになります。
要は、dockerを搭載しているLinux自体をスキャン対象にして試してみようと思ってhostの記載を"localhost"や"127.0.0.1"にしても接続できなくなります。
この際に出るエラーが、ちょっとわかりにくいんですよ。。

```
[May 26 01:20:47] ERROR [localhost] (1/1) Failed: remotehost, err: [Failed to ssh-keyscan. cmd: /usr/bin/ssh-keyscan -p 22 localhost, err:
    github.com/future-architect/vuls/scanner.validateSSHConfig
        /go/src/github.com/future-architect/vuls/scanner/scanner.go:447
  - exit status 1]
```

最初鍵が悪いのかな、、？と思って調べてたのですが、結論としては、コンテナにとってのlocalhostはコンテナの事であり、ホストOS側のことではないということですね。
ホストにsshさせるつもりで設定していましたが、コンテナに接続しようとしちゃっていた、ということです。

## report結果はどこへゆく？

report.shを実行する場合、内部でvulsに-format-listが入っていて、それにより標準出力に照合結果が出てきます。

人間が見る分にはいいのですが、切り貼りしてレポートに、、としようとするとやりづらいので、csvやjson出だしたくなります。
それっぽいオプションとして、format-csvやformat-jsonがあるのですが、、、
report.sh -format-csvとしても、標準出力にcsv型で結果が表示されることはありません。

ここらの話をまとめておこうかと思います。

### 照合結果の実態

report.shを実行したディレクトリ直下のresult/yyyy-mm-ddThh-MM-ss+0000の下に、XXX.jsonがあります。
XXXは、config.tomlでserver.XXXとした部分（サーバ名ですかね）。
これが、スキャン結果兼、照合結果になるようです。

scan.sh実行直後は、CVE情報がついてない状態で配置されていて、report.shを実行すると、CVE情報がscannedCves部に追記されていくようです。

### 標準出力で使えるフォーマット

そもそも、format-jsonやcsvは標準出力の選択肢としては使えなとのこと。
https://vuls.io/docs/ja/usage-report.html#example-of-three-format-options

厄介なのが、format-jsonをつけても特にアラートとが出るわけでもないってことなんですよね。。

format-csvを使うときは、一緒に-to-localfileを指定してやればいいようです。
但し、結果は標準出力ではなくてresult/yyyy...の方にXXX.csvとして配置されます。
format-jsonは、to-localfileを指定しても反応無し。
まぁ、元になっているXXX.jsonがjsonファイルなわけだし、やってもしょうがないだろうと言うことでしょうか。

### 任意のフォーマットで出力しようと思ったら

一回report.shを空打ちしてXXX.jsonにCSV情報を付与。
で、出力はreport.shは頼らずにXXX.jsonを直にjqにかける、というのが妥当でしょうか。
例としてはこんな。

```
cat ./remotehost.json | jq -r '(.scannedCves[] | [ affecredPackages[].name, .cveID, .cveContents.nvd[].cvss2Score, .cveContents.nvd[].summary ] ) | @csv'

# jq -r: 出力時に文字列を"で囲わない。今回は最後にCSVにするが、CSV自体が各データを"で囲う仕様なので、-rつけないとあとの取り扱いで困る。
# ( ... ) | @csv: ...の処理は後述。()で生成された配列をCSV形式に変換して標準出力に渡す。
# [ ... ]: ...で並べたデータ群をlistとして束ねる
# .snannedCves[] |: CVEデータは、snannedCvesというキー名称でデータ構造体の直下にdictとしてぶら下がっている。[]をつけて、各dictのValueを配列にして、パイプで１行ずつ、右の処理に渡す。この際、key情報であるCVEの文字列が失われるのだが、CVEはValueの中にも入っているので、問題ない。
# .cveID, ...: パイプ左の処理から渡される１行（1dict)に対してほしいデータをまとめる。パイプから渡された時点で、.scannedCVE配下の各dictのValueに対しての処理になっているので、パスの指定は.scannedCves....ではなく、いきなり.cveIDなどでOK。

```

エクセルなどに転記して使うように空きの列入れたいときは、[]の中で", null"ってのを足してあげればOK。
基本的にNVDには常にデータ入ってる、、とは思うのですが。NVD似データが入っていないが他のソースに入っているということはありえます。
そういう場合に別のソースの情報を表示に持ってくるみたいなif文もかけるようなのですが、、そこまで行くならpythonで２０行くらいのスクリプト書くほうが楽な気がします。
ちょっと分析したいこともあるので、そこらは別途整理します。

# まとめ

自分の用途で使う場合のVulsの構成や使い方についてまとめました。
さて、また来年読み返したときに、、どうなってることやら。