VulsのcpeNamesで、新しく実装されたpseudoを利用する

# 概要
Vulsで最近実装された、cpeNamesでのpseudoの利用方法を記載します。

今までは、ホストの項目にcpeNamesを追加する必要があった。
例えば「ネットワーク機器のcpeNamesを登録する」場合は、どこかのホストに追加で設定をする必要があった。この場合、`cpe:/...` の名前のパッケージとして扱われてしまい、見づらかった。

`type=pseudo`が導入されたことで、cpeNamesでの検査結果が見やすくなる。

## 注意事項

そもそも、NVDにCPEが登録されていない場合があります。

- 例えば、1-2年前は、WordPressのバージョンが3系までしか登録されていませんでした。
    - いまは、きちんと登録されています。
- 登録のない製品等もあります。
    - 例えばYamahaルータの RT1200はありますが、RT1210がない、など。

CPE情報が更新されるかは、NVDのみぞ知る、かもしれません。

- CPEを検索し、直近のバージョンまで登録されているのであれば、今後も登録されていく可能性は高いです。
    - 検索した結果、メジャーバージョン1つ前までしか登録がないような場合、おそらくCPE情報は更新されず、Vulsに登録しても有用な結果は得られない可能性があります（Vulsのせいではなく、CPE情報自体が無いため）。
    - 登録しておく分には問題ないので、とりあえず登録しておいてCPEが更新されるのを待つ、という戦略もありかとは思います。

# 使ってみる
## vulsをバージョンアップする

2017/11/06に更新された版、以降のVulsを利用する必要があります。
そうでない場合は、後述の正しい設定をしても以下のようなエラーが出ます。

- もう修正済みなので、とりあえずアップデートしやがってくださいませ

```
vuls@localhost:~$ vuls configtest
[Nov  1 00:00:00] ERROR [localhost] Error loading /opt/vuls/config.toml, network is invalid. User is empty
[Nov  1 00:00:00] ERROR [localhost] If you update Vuls and get this error, there may be incompatible changes in config.toml
[Nov  1 00:00:00] ERROR [localhost] Please check README: https://github.com/future-architect/vuls#configuration
vuls@localhost:~$ 
```

## config.tomlを編集する

通常 [servers] 以下に [servers.HOSTNAME] を書いていますが、新たなホストとしてcpeをまとめるものを作ります。
例えば、ホスト名が network としてまとめられるのを期待する場合は、以下のようにします。

```
[default]

[servers]

[servers.localhost]
host = "localhost"
port = "local"

[servers.network]
type="pseudo"
cpeNames = [
  "cpe:/o:cisco:ios:15.5t",
  "cpe:/o:yamaha:rtx1200:10.01.22",
  "cpe:/o:yamaha:rtx1100:8.03.83",
]
```

上記configで、以下のような表示が期待されます。

- ホスト名:localhost で、ローカルスキャンを行う
- ホスト名:network で、Cisco IOS, YAMAHA RTX1100/RTX1200 のファームウェア監視
    - ホストのスキャンと異なり、`host`や`port`の項目が不要。`type=pseudo`と`cpeNames`項目だけで良くなりました。

## cpeNamesを取得する。

例えば Cisco IOSであれば、go-cpe-dictionaryのDBである cpe.db を使って確認します。

```
vuls@localhost:~$ sqlite3 ./cpe.db 'select name from cpes' | grep cisco | grep ios | grep 15
cpe:/a:cisco:ios:15.2%282%29ea
cpe:/a:cisco:ios:15.2%282%29ea1
cpe:/a:cisco:ios:15.2%282%29eb
cpe:/a:cisco:ios:15.2%282%29eb1
cpe:/o:cisco:ios:11.1%2815%29
...
vuls@localhost:~$ sqlite3 ./cpe.db 'select name from cpes' | grep cisco | grep ios:15.6
cpe:/o:cisco:ios:15.6%280.17%29t
cpe:/o:cisco:ios:15.6%281%29t0a
cpe:/o:cisco:ios:15.6%282%29sn
cpe:/o:cisco:ios:15.6%282%29sp
cpe:/o:cisco:ios:15.6%282%29sp1
cpe:/o:cisco:ios:15.6%283%29m
cpe:/o:cisco:ios:15.6%283%29m1b
cpe:/o:cisco:ios:15.6%283%29m2
cpe:/o:cisco:ios:15.6%283%29m2a
cpe:/o:cisco:ios:15.6%283%29m3
vuls@localhost:~$ 
```

これを見て、例えば、15.6(3)m3 であれば`cpe:/o:cisco:ios:15.6%283%29m3`を登録します。

探す場合は、小文字でベンダ名や製品などを入れ、CPE名のパターンを見て登録するのがよさそうです。

## スキャンをする

いつも通りスキャンをしてみます。

- スキャン時に、`Detected: network: pseudo`で認識しているみたい。

```
vuls@terra00:~/scripts$ ./vuls-scan 
[Nov  1 00:00:00]  INFO [localhost] Start scanning
[Nov  1 00:00:00]  INFO [localhost] config: /opt/vuls/config.toml
[Nov  1 00:00:00]  INFO [localhost] Validating config...
[Nov  1 00:00:00]  INFO [localhost] Detecting Server/Container OS... 
[Nov  1 00:00:00]  INFO [localhost] Detecting OS of servers... 
[Nov  1 00:00:00]  INFO [localhost] (1/2) Detected: network: pseudo 
[Nov  1 00:00:00]  INFO [localhost] (2/2) Detected: localhost: ubuntu 16.04
[Nov  1 00:00:00]  INFO [localhost] Detecting OS of containers... 
[Nov  1 00:00:00]  INFO [localhost] Detecting Platforms... 
[Nov  1 00:00:03]  INFO [localhost] (1/2) network is running on other
[Nov  1 00:00:03]  INFO [localhost] (2/2) localhost is running on other
[Nov  1 00:00:03]  INFO [localhost] Scanning vulnerabilities... 
[Nov  1 00:00:03]  INFO [localhost] Open boltDB: /opt/vuls/cache.db
[Nov  1 00:00:03]  INFO [localhost] Scanning vulnerable OS packages...
[Nov  1 00:00:03]  INFO [localhost] apt-get update...
...
```

VulsRepoで見てみると、Hostnameがlocalhostとnetworkの二つになっている。
![cpeNames-pseudo.png](https://qiita-image-store.s3.amazonaws.com/0/124868/914f3c73-3b0e-feac-4e3c-cff63849926a.png)

ここで、左側にPackageを追加すると、RTX1200とCiscoIOSの評価が見える。
![cpeNames-pseudo2.png](https://qiita-image-store.s3.amazonaws.com/0/124868/2a85f924-ae8c-9922-339f-468f6eea932c.png)

- RTX1100の記載がないのは、登録した8.03.83は最終リリースひとつ前であり、最終リリースにCVEが割り当てられた脆弱性が含まれていない、為と思われる。

# cpeNames

CPEについての概要は、[IPA](https://www.ipa.go.jp/security/vuln/CPE.html)の資料を参照

必要そうなcpeNamesの取得の仕方を書いておきます。

- cpe.db のあるディレクトリで、以下を実行しつつ確認する。
    - `$ sqlite3 ./cpe.db 'select name from cpes' | grep "<調べたいもの>"`
- 色々、同じような名前が出てくるけど、どれを選ぶの？
    - まずは種別
        - `cpe:/h:…` の物は、ハードウェア
            - `cpe:/h:cisco:catalyst_2950:-`は、Cisco Catalyst2950。
        - `cpe:/o:…` の物は、OS
            - `cpe:/o:google:android:7.1.2`は、Android7系最後のもの。
        - `cpe:/a:…` の物は、アプリケーション
            - `cpe:/a:apache:struts:2.3.33` は、Apache Struts2.3 系
    - ベンダ名なり、製品名なりで、最新版-1のバージョンがあればそれを利用する。
        - 例えば、Apache Strutsであれば2.3/2.5がある。
        - 最新バージョンは、CPEには登録されないようだ。
            - 更新があった時に、ひとつ前のバージョンとしてCPEに登録される？

物によりますが、例えば、VMwareTools （`cpe:/a:vmware:tools:9.4.5`） も登録されています。

# まとめ

前述のように [servers.まとめるための名前]に`type="pseudo"`を付けて`cpeNames`を書くだけです。

ネットワーク機器の台数が少なければルータごとにserversでまとめてもいいですし、バージョンが統一されているなら代表して1個だけ登録しておくことも可能です。

また、サーバが所属するシステムごとにcpeNameをまとめてもいいかもしれません。

- 人事システムのStrutsやルータのcpeNames、営業課のwordpressやルータのcpeNames、など。
    - 今まではホスト依存で登録していたので、これをシステムごとにしてしまう等。

最後に、当たり前ながら **ネットワーク機器のファームウェアを見る場合、既存のファームウェアバージョンを知っている必要がある** 事に注意してください。