Security Index

セキュリティやソフトウェアについてのあれこれ

Vulsのコードを読む その1 全体像の把握

脆弱性スキャナ Vulsのコードを読んで理解を深めていきたいと思います。

 

GitHub - future-architect/vuls: Agent-less vulnerability scanner for Linux, FreeBSD, Container Image, Running Container, WordPress, Programming language libraries, Network devices

 

f:id:security_index:20191104162708p:plain

 

今回は、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 syntax

Subcommands 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上で関数名をダブルクリックするとその関数の定義や参照している部分へ簡単に飛べる機能がありコードを読み進めるのが結構楽にできます。

 

f:id:security_index:20191104162453p:plain

 

その他

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

 

 

スターティングGo言語

Goならわかるシステムプログラミング