Vuls using Docker on Windows

[IPAテクニカルウォッチ「脆弱性対策の効果的な進め方（ツール活用編）」]( https://www.ipa.go.jp/security/technicalwatch/20190221.html)に遭遇。

ちょうど脆弱性検査ツールを検証、導入したいと考えていたので実践してみました。

## 構築環境

- Windows 10 1809
- Docker Desktop 2.0.0.3 (31259)
- WSL（Dockerの操作に利用）
  - Docker version 18.06.0-ce

### Dockerイメージ取得

```bash
docker pull vuls/go-cve-dictionary
docker pull vuls/goval-dictionary
docker pull vuls/gost
docker pull vuls/vuls
```

### 作業ディレクトリの作成

```bash
mkdir vuls
cd vuls/
mkdir go-cve-dictionary-log goval-dictionary-log gost-log vuls-log
```

### fetch JVN

JVNより1998年から作業年までの脆弱性情報を取得する。

```bash
for i in `seq 1998 $(date +"%Y")`; do docker run --rm -it -v $PWD:/vuls -v $PWD/go-cve-dictionary-log:/var/log/vuls vuls/go-cve-dictionary fetchjvn -years $i; done
```

### fetch NVD

NVDより2002年から作業年までの脆弱性情報を取得する。

```bash
for i in `seq 2002 $(date +"%Y")`; do docker run --rm -it -v $PWD:/vuls -v $PWD/go-cve-dictionary-log:/var/log/vuls vuls/go-cve-dictionary fetchnvd -years $i; done
```

### fetch OVAL

OSのOVAL情報を取得する。（OSの脆弱性情報のようです）

```bash
docker run --rm -it -v $PWD:/vuls -v $PWD/goval-dictionary-log:/var/log/vuls vuls/goval-dictionary fetch-redhat 5 6 7
```

### fetch gost(Go Security Tracker)

RedhatやDebian等で公開された脆弱性情報を所得するようです。

```bash
docker run --rm -it -v $PWD:/vuls -v $PWD/gost-log:/var/log/gost vuls/gost fetch redhat after=2016-01-01
```

### Configuration

リモートサーバの脆弱性検査を行います。ここでやることは、SSHで接続できるように準備を行う感じです。

- 鍵の生成

```bash
ssh-keygen -t rsa
```

- 鍵のコピー

```shell-session
# ssh-copy-id xxx@10.64.xx.xx
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '10.64.xx.xx (10.64.xx.xx)' can't be established.
ECDSA key fingerprint is SHA256:y7rfWbg23FBZC2A0SE/qMJtHAMHQGSYsl2qakQUPpP8.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Password for xxx@10.64.xx.xx:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'xxx@10.64.xx.xx'"
and check to make sure that only the key(s) you wanted were added.
```

- 接続設定のファイル

```bash:config.toml
[servers]

[servers.10-64-xx-xx]
host = "10.64.xx.xx"
port = "22"
user = "xxx"
keypath = "/root/.ssh/id_rsa"
```

### Configtest

このコマンドでできるらしいがうまくいきませんでした。

```shell-session
# docker run --rm -it -v ~/.ssh:/root/.ssh:ro -v $PWD:/vuls -v $PWD/vuls-log:/var/log/vuls vuls/vuls configtest -config=./config.toml
[Feb 23 03:23:43] ERROR [localhost] Error loading ./config.toml, 10-64-xx-xx is invalid. keypath: /root/.ssh/id_rsa not exists
[Feb 23 03:23:43] ERROR [localhost] If you update Vuls and get this error, there may be incompatible changes in config.toml
[Feb 23 03:23:43] ERROR [localhost] Please check README: https://github.com/future-architect/vuls#configuration
```

次のようなコマンドでコンテナー内の様子を確認したところ、原因は、`/root/.ssh`のパーミッションが間違い、中身がない、ことのようです。

```shell-session
# docker run --rm -it -v ~/.ssh:/root/.ssh:ro -v $PWD:/vuls -v $PWD/vuls-log:/var/log/vuls --entrypoint "/bin/ls" vuls/vuls -al /root
total 8
drwx------    1 root     root          4096 Feb 23 08:52 .
drwxr-xr-x    1 root     root          4096 Feb 23 08:52 ..
drwxr-xr-x    2 root     root            40 Feb 23 01:55 .ssh
# docker run --rm -it -v ~/.ssh:/root/.ssh:ro -v $PWD:/vuls -v $PWD/vuls-log:/var/log/vuls --entrypoint "/bin/ls" vuls/vuls -al /root/.ssh
total 4
drwxr-xr-x    2 root     root            40 Feb 23 01:55 .
drwx------    1 root     root          4096 Feb 23 08:52 ..
```

うまくできないのは、Windows環境でやっているためでした。

参考：[Docker Tip #56: Volume Mounting SSH Keys into a Docker Container](https://nickjanetakis.com/blog/docker-tip-56-volume-mounting-ssh-keys-into-a-docker-container)

対策として、`.ssh`を作業ディレクトリにコピーと、魔法のシェルを準備（リモートサーバの接続設定が増えるたびに、`.ssh`をコピーする必要がある）

```shell-session
# cp -rp /root/.ssh .
# cat docker-entrypoint.sh
#!/bin/sh
set -e

cp -R /tmp/.ssh /root/.ssh
chmod 700 /root/.ssh
chmod 644 /root/.ssh/id_rsa.pub
chmod 600 /root/.ssh/id_rsa

exec "$@"
```

以下のようなDockerコマンドで、パーミッションやファイルが届いていることを確認しました。

```shell-session
# docker run --rm -it -v $PWD/.ssh:/tmp/.ssh -v $PWD:/vuls -v $PWD/vuls-log:/var/log/vuls --entrypoint "sh" vuls/vuls /vuls/docker-entrypoint.sh ls -alR /root
/root:
total 12
drwx------    1 root     root          4096 Feb 23 10:31 .
drwxr-xr-x    1 root     root          4096 Feb 23 10:31 ..
drwx------    2 root     root          4096 Feb 23 10:31 .ssh

/root/.ssh:
total 20
drwx------    2 root     root          4096 Feb 23 10:31 .
drwx------    1 root     root          4096 Feb 23 10:31 ..
-rw-------    1 root     root          1679 Feb 23 10:31 id_rsa
-rw-r--r--    1 root     root           395 Feb 23 10:31 id_rsa.pub
-rwxr-xr-x    1 root     root           222 Feb 23 10:31 known_hosts
```

ようやく`Configtest`が成功

```shell-session
# docker run --rm -it -v $PWD/.ssh:/tmp/.ssh -v $PWD:/vuls -v $PWD/vuls-log:/var/log/vuls --entrypoint "sh" vuls/vuls /vuls/docker-entrypoint.sh vuls configtest -config=./config.toml
[Feb 23 10:32:48]  INFO [localhost] Validating config...
[Feb 23 10:32:48]  INFO [localhost] Detecting Server/Container OS...
[Feb 23 10:32:48]  INFO [localhost] Detecting OS of servers...
[Feb 23 10:32:49]  INFO [localhost] (1/1) Detected: 10-64-xx-xx: freebsd 10.2-RELEASE-p28
[Feb 23 10:32:49]  INFO [localhost] Detecting OS of containers...
[Feb 23 10:32:49]  INFO [localhost] Checking Scan Modes...
[Feb 23 10:32:49]  INFO [localhost] Checking dependencies...
[Feb 23 10:32:50]  INFO [10-64-xx-xx] Dependencies... No need
[Feb 23 10:32:50]  INFO [localhost] Checking sudo settings...
[Feb 23 10:32:50]  INFO [10-64-xx-xx] sudo ... No need
[Feb 23 10:32:50]  INFO [localhost] It can be scanned with fast scan mode even if warn or err messages are displayed due to lack of dependent packages or sudo settings in fast-root or deep scan mode
[Feb 23 10:32:50]  INFO [localhost] Scannable servers are below...
10-64-xx-xx
```

### Scan

このコマンドらしいがまたしてもエラー

```shell-session
# docker run --rm -it -v $PWD/.ssh:/tmp/.ssh -v $PWD:/vuls -v $PWD/vuls-log:/var/log/vuls -v /etc/localtime:/etc/localtime:ro -e "TZ=Asia/Tokyo" --entrypoint "sh" vuls/vuls /vuls/docker-entrypoint.sh vuls scan -config=./config.toml
docker: Error response from daemon: OCI runtime create failed: container_linux.go:344: starting container process caused "process_linux.go:424: container init caused \"rootfs_linux.go:58: mounting \\\"/etc/localtime\\\" to rootfs \\\"/var/lib/docker/overlay2/c88697346e932555b2d5c786c2c2d550a999a3bb515a3d97bb9da7a74a7a42e1/merged\\\" at \\\"/var/lib/docker/overlay2/c88697346e932555b2d5c786c2c2d550a999a3bb515a3d97bb9da7a74a7a42e1/merged/etc/localtime\\\" caused \\\"not a directory\\\"\"": unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type.
```

`/`（ルート）からファイルをとってくることが難しいのかもしれないので、ホームディレクトリにコピーして実行した

```shell-session
# cp -rp /etc/localtime .
# docker run --rm -it -v $PWD/.ssh:/tmp/.ssh -v $PWD:/vuls -v $PWD/vuls-log:/var/log/vuls -v $PWD/localtime:/etc/localtime:ro -e "TZ=Asia/Tokyo" --entrypoint "sh" vuls/vuls /vuls/docker-entrypoint.sh vu
ls scan -config=./config.toml
[Feb 23 10:39:57]  INFO [localhost] Start scanning
[Feb 23 10:39:57]  INFO [localhost] config: ./config.toml
[Feb 23 10:39:57]  INFO [localhost] Validating config...
[Feb 23 10:39:57]  INFO [localhost] Detecting Server/Container OS...
[Feb 23 10:39:57]  INFO [localhost] Detecting OS of servers...
```

なんとか実行できました。

PROXY環境下なので、`--http-proxy`を追加しました。

```shell-session
# docker run --rm -it -v $PWD/.ssh:/tmp/.ssh -v $PWD:/vuls -v $PWD/vuls-log:/var/log/vuls -v $PWD/localtime:/etc/localtime:ro -e "TZ=Asia/Tokyo" --entrypoint "sh" vuls/vuls /vuls/docker-entrypoint.sh vuls scan -config=./config.toml --http-proxy="xxx.xx.x.xxx:8080"
```

検査中に、以下のようなコマンドが発行されるようですが、私の環境ではエラーとなりました。
sshで接続先ユーザのログインシェルがborn shell系である前提のコマンドです。（FreeBSDでは、tcshを愛用している私の環境では使えませんでした。仕方なくログインシェルを変更しました）

```shell-session
 http_proxy="xxx.xx.x.xxx:8080" https_proxy="xxx.xx.x.xxx:8080" HTTP_PROXY="xxx.xx.x.xxx:8080" HTTPS_PROXY="xxx.xx.x.xxx:8080" pkg version -v
  exitstatus: 1
  stdout: http_proxy=xxx.xx.x.xxx:8080: Command not found.
````

ここまでやって、ようやく結果が出力されました。

```shell-session
One Line Summary
================
10-64-xx-xx     freebsd10.2-RELEASE-p28 113 installed, 0 updatable



To view the detail, vuls tui is useful.
To send a report, run vuls report -h.
```

### Scan report

- one-line summary

```shell-session
# docker run --rm -it -v $PWD/.ssh:/tmp/.ssh -v $PWD:/vuls -v $PWD/vuls-log:/var/log/vuls -v $PWD/localtime:/etc/localtime:ro -e "TZ=Asia/Tokyo" --entrypoint "sh" vuls/vuls /vuls/docker-entrypoint.sh vuls report -format-one-line-text

<省略>

One Line Summary
================
10-64-xx-xx     Total: 230 (High:89 Medium:136 Low:5 ?:0)       0/230 Fixed     113 installed, 0 updatable      0 exploits      en: 0, ja: 2 alerts
160-xx-x-xx     Total: 1559 (High:508 Medium:939 Low:112 ?:0)   0/1559 Fixed    643 installed                   0 exploits      en: 15, ja: 19 alerts
```

## その他のエラー

### ERROR [160-xx-x-xx] yum-utils is not installed

検査対象のサーバに、`yum-utils`がインストールされている必要がある。入れたくないので、オフラインだと宣言して回避

```shell-session:config.toml
[servers.160-xx-x-xx]
host = "160.xx.x.xx"
port = "22"
user = "xxx"
keyPath = "/root/.ssh/id_rsa"
scanMode = ["fast", "offline"]
```

### scanMode err: Remove offline scan mode, FreeBSD needs internet connection

FreeBSDの場合、`pkg audit -F -r -f /tmp/vuln.db`を実行するので、オンライン接続が必須、回避不可

こんなエラーが出ます

```shell-session
pkg: http://vuxml.freebsd.org/freebsd/vuln.xml.bz2: Operation timed out
pkg: cannot fetch vulnxml file
```

## 所感

- Dockerで環境が構築できることはすごく楽
- Docker on Windowsは、ハメられた
- リモート端末に対して検査が行えることはGood
- SSHを要求するため、不特定多数の端末を検査する業務ではしんどい
- Windowsが検査できないので、きっと使わない