Vulsはリモートスキャン対象サーバで何をしているのか

# はじめに
Vuls、勝手に脆弱性のあるパッケージを見つけてくれて便利ですよね。
リモートスキャンを使えば、スキャン対象のサーバにインストールする必要もなく、SSHで入って勝手になんか見つけてきてくれます。
でも、本番サーバにSSHで入られるのは少し怖い…
もし問題が起きたときに、スキャンしたせいじゃ無いですよ！と言える根拠が欲しいと思ったので、具体的にどんなことをスキャン対象サーバで行っているのか、調べてみました。

調査方法は以下の通りです。`auditctl`でローカル側で実行されたコマンドを全てログし、後から解析してみました。

```
auditctl -a always,exit -F arch=b64 -S execve
vuls サブコマンド
auditctl -D
cat /var/log/audit/audit.log | grep "EXECVE"
```

## 環境
ローカル

```
# cat /etc/centos-release
CentOS Linux release 7.7.1908 (Core)
# go version
go version go1.14.2 linux/amd64
# vuls -v
vuls v0.9.5 build-20200518_192222_466ec93
```

スキャン対象

```
# cat /etc/centos-release
CentOS Linux release 7.7.1908 (Core)
```

# 結果
## コマンドの実行方法
リモートサーバでコマンドを実行するときは、以下のような手法で行っているようです。
`ControlMaster`を用いてTCPコネクションを集約したり、ログイン後のウィンドウ幅を1000にしたりしています。

```
/usr/bin/ssh 
  -tt
  -o StrictHostKeyChecking=yes
  -o LogLevel=quiet
  -o ConnectionAttempts=3
  -o ConnectTimeout=10
  -o ControlMaster=auto
  -o ControlPath=/root/.vuls/controlmaster-%r-hoge.%p
  -o Controlpersist=10m vuls@ホスト名
  -p 22
  -i /root/.ssh/id_hoge
  -o PasswordAuthentication=no
    stty cols 1000; 実行するコマンド
```

コマンド本体は、以下のように16進数で送られているようです。記号とかで予期しない動作になるのを防いでいると思われます。

```
7374747920636F6C7320313030303B206C73202F6574632F64656269616E5F76657273696F6E
-> stty cols 1000; ls /etc/debian_version
```

**以下では、`stty cols 1000;`までを省略して`(SSH)`と書きます。**

## configtest
configtestでは、以下のコマンドが実行されていました。
単純にOSのバージョン情報を取得しているだけですね。今回は、対象サーバがCentOSだったので、それを`cat`しているようです。（いつもredhat-releaseを見ていたのですが、centos-releaseもあるんですね…）

```
vuls configtest
(SSH) ls /etc/debian_version
(SSH) ls /etc/fedora-release
(SSH) ls /etc/oracle-release
(SSH) ls /etc/centos-release
(SSH) cat /etc/centos-release
```


## fast-offline
fast-offlineモードでは、以下のコマンドが実行されていました。
前半はconfigtestと同じで、対象サーバのOSバージョンを取得しています。
その後、IPアドレスの取得、カーネルのバージョン？の取得、インストールされているパッケージの列挙となっています。IPアドレスはofflineの有無に関わらず、[ここ](https://github.com/future-architect/vuls/blob/466ec93d8e53150dda60a54d428046fac744579f/scan/redhatbase.go#L165)で取得しているようです。

```
vuls scan hoge
(SSH) ls /etc/debian_version
(SSH) ls /etc/fedora-release
(SSH) ls /etc/oracle-release
(SSH) ls /etc/centos-release
(SSH) cat /etc/centos-release
(SSH) /sbin/ip -o addr
(SSH) uname -r
(SSH) rpm -qa --queryformat "%{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE} %{ARCH}\n"
(SSH) rpm -q --last kernel
```

## fast
fastモードでは、以下のコマンドが実行されていました。
fast-offlineモードに加え、
1. AWSで動いているかの確認、動いていればインスタンスIDの取得？
2. yumリポジトリデータのダウンロード
3. dnfが入っているかのチェック（yumの代わりにdnfが入っていたらコマンドが変わる…？）
4. repoqueryでアップデート可能なバージョンを検索する（[dnfだったらオプションが微妙に違う](https://github.com/future-architect/vuls/blob/466ec93d8e53150dda60a54d428046fac744579f/scan/redhatbase.go#L352)）

オンプレで動いていても`169.254.169.254`に通信を飛ばそうとするんですね。

```
vuls scan hoge
(SSH) ls /etc/debian_version
(SSH) ls /etc/fedora-release
(SSH) ls /etc/oracle-release
(SSH) ls /etc/centos-release
(SSH) cat /etc/centos-release
(SSH) type curl
(SSH) curl --max-time 1 --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id
(SSH) /sbin/ip -o addr
(SSH) uname -r
(SSH) rpm -qa --queryformat "%{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE} %{ARCH}\n"
(SSH) rpm -q --last kernel
(SSH) yum makecache --assumeyes
(SSH) repoquery --version | grep dnf
(SSH) repoquery --all --pkgnarrow=updates --qf='%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{REPO}'
```


# まとめ
いかがでしたか？特に環境を変えるようなことはしていないことが分かりましたね！（当然）
強いて言えばIPアドレスやインスタンスIDの取得は必要でない場合もあると思うので、オプションでコマンドを発行しないようにできると、不必要な情報が取得されず安心かなと思いました。

もちろん変なことはしていないと思っていましたが、今回自分で確認してより安心できました。