脆弱性スキャナ Vulsのコードを読んで理解を深めていきたいと思います。
今回は、scan周りに注目してvulsのコードの全体像の把握を行なっています。
全体像
main.go
mainパッケージのmain関数があり、一番初めに実行される部分。
コマンドラインの引数を読み取り、その引数に割り当てられた機能を実行する。
GoogleのsubcommandsというGoのパッケージを使ってコマンドラインツールの作成を行なっています。
以下のsubcommands.Registerの部分でサブコマンドの登録を行なっています。
登録されるサブコマンドの詳細は、次に説明する commands/ ディレクトリの中に書かれています。
func main() {
subcommands.Register(subcommands.HelpCommand(), "")
subcommands.Register(subcommands.FlagsCommand(), "")
subcommands.Register(subcommands.CommandsCommand(), "")
subcommands.Register(&commands.DiscoverCmd{}, "discover")
subcommands.Register(&commands.TuiCmd{}, "tui")
subcommands.Register(&commands.ScanCmd{}, "scan")
subcommands.Register(&commands.HistoryCmd{}, "history")
subcommands.Register(&commands.ReportCmd{}, "report")
subcommands.Register(&commands.ConfigtestCmd{}, "configtest")
subcommands.Register(&commands.ServerCmd{}, "server")
今回は、scan周りについて注目していきたいのでScanCmd{} (scan.go)に焦点を当てて進めていきます。
commands/
- configtest.go
- discover.go
- history.go
- report.go
- scan.go
- server.go
- tui.go
- util.go
subcommandsで割り当てるコマンドが書かれている。
以下のコードはscan.goの抜粋です。
// Name return subcommand name
func (*ScanCmd) Name() string { return "scan" }
// Synopsis return synopsis
func (*ScanCmd) Synopsis() string { return "Scan vulnerabilities" }
// Usage return usage
func (*ScanCmd) Usage() string {
return `scan:
scan
[-config=/path/to/config.toml]
[-results-dir=/path/to/results]...
`
}
// SetFlags set flag
func (p *ScanCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&c.Conf.Debug, "debug", false, "debug mode")....
}
// Execute execute
func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {...
}
Name()に"scan"
Synopsis()に"Scan vulnerabilities"
Usage()に[-config=/path/to/config.toml]
をreturnするようにすることで
vuls -help 時にこれらの内容を表示するようにできます。
$ vuls -help
Usage: vuls <flags> <subcommand> <subcommand args>Subcommands:
commands list all command names
flags describe all known top-level flags
help describe subcommands and their syntaxSubcommands for scan:
scan Scan vulnerabilities
SetFlags()ではdebugモードのon/offなどのフラグなどの制御のための設定を記述します。
ここも、vuls scan -help 時にflag一覧を表示することができます。
$ vuls scan -help
scan:
scan
[-config=/path/to/config.toml]
-debug
debug mode
Execute()の中身が実際に実行されるコードになります。
フラグに設定された条件に合わせて処理を変えることができます。
scan/
- amazon.go
- centos.go
- container.go
- debian.go
- serverapi.go
...
これらのファイルは、commands/scan.go のExecute()の処理の中の具体的なscan機能を実現している部分。
commands/scan.goからはscan/serverapi.go の関数が呼ばれ、serverapi.goがcontainer.goの関数を呼ぶというフローになっている。
commands/scan.goのExecute()の一部
// commands/scan.go
util.Log.Info("Detecting Server/Container OS... ")
if err := scan.InitServers(p.timeoutSec); err != nil {
util.Log.Errorf("Failed to init servers: %+v", err)
return subcommands.ExitFailure
}
scan.InitServers()はscan/serverapi.goの関数
// scan/serverapi.go
// InitServers detect the kind of OS distribution of target servers
func InitServers(timeoutSec int) error {needBaseServers, scanContainer, scanImage := needScans()
// use global servers, errServers when scan containers and images
servers, errServers = detectServerOSes(timeoutSec)...
func detectServerOSes(timeoutSec int) (servers, errServers []osTypeInterface) {
...
osTypeChan <- detectOS(s)
...
func detectOS(c config.ServerInfo) (osType osTypeInterface) {
...
itsMe, osType, fatalErr = detectContainerImage(c)
detectContainerImage()がscan/container.goの関数となっています。
scan/serverapi.goがcommands/scan.goから呼ばれるAPIとなっており、scan/container.goなどがより詳細な機能を実現する役割になっているようです。
vulsのscanを実行した時の流れ
main.go -> commands/scan.go -> scan/serverapi.go -> scan/container.go
Github上で関数名をダブルクリックするとその関数の定義や参照している部分へ簡単に飛べる機能がありコードを読み進めるのが結構楽にできます。
その他
go.mod
Go 1.11から利用できるもの
依存ライブラリ一覧が記載されている
go mod initで初期化し、go buildを実行すると自動で生成される
https://syfm.hatenablog.com/entry/2019/08/10/170730
https://qiita.com/propella/items/e49bccc88f3cc2407745
https://qiita.com/kwmt@github/items/f16c8a7e07e281afb9a2
go.sum
依存ライブラリ一覧とそのハッシュ値を含むもの
ビルド時に正しいかどうかの確認がされる
owasp-dependency-check/
Java, .Net、実験段階だがPython, Ruby, PHP (composer), Node.jsの依存ライブラリの脆弱性をスキャンするもの。
https://jeremylong.github.io/DependencyCheck/
https://kazuhira-r.hatenablog.com/entry/2019/06/29/213406
https://github.com/jeremylong/DependencyCheck
owasp-dependecy-checkは気になるので今度詳細に調べて見ます。
次回はscan周りをさらに掘り下げて調べてみたいと思います。
その2、その3、その4はこちら。
Vulsのコードを読む その2 go-cve-dictionary を理解する、バグを見つけてプルリクを出してマージされるまで - Security Index
Vulsのコードを読む その3 Vuls scanを調べてみた - Security Index
Vulsのコードを読む その4 Vuls reportを調べてみた - Security Index