vulsのコアのアルゴリズムについて
こんにちは、
かずみん (@warugaki_k_k) | Twitter
です。
ブログのタイトルは、ほんとは違うかも。本当は全然コアじゃないのかもしれないです。
vulsって結局どうやって脆弱性判断しているのかわからなくて、コード読みました。そしてわかったことを書きます。
どっかで読んだ記憶によると、OVALと言うもので検知されてる。何それわからない。
ovalのデータ構造やら。わかりませんでした。
(ここで、コードを読むまでの予想だが、バージョンとcveが一対一やら、なんやかんやになってる。と予想。それをどうやって流のかが不明。
まー、scan時に取得されたversionが脆弱性を含むかをfillするのは、report時なので、そのへんのコードを読むと、こんなのがgetDefsByPackNameFromOvalDB関数の
245 definitions, err := driver.GetByPackName(r.Family, r.Release, req.packName, req.arch)
多分ここで、検査してるんだろうけど、どうやら、これは、goval-dictionaryのGetByPackName()を呼び出しているようだ。
ま、見てみると。ここで色々データを取ってくるみたい。
func (o *RedHat) GetByPackName(driver *gorm.DB, osVer, packName, _ string) ([]models.Definition, error) { osVer = major(osVer) packs := []models.Package{} err := driver.Where(&models.Package{Name: packName}).Find(&packs).Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } defs := []models.Definition{} for _, p := range packs { def := models.Definition{} err = driver.Where("id = ?", p.DefinitionID).Find(&def).Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } root := models.Root{} err = driver.Where("id = ?", def.RootID).Find(&root).Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } if root.Family == config.RedHat && major(root.OSVersion) == osVer { defs = append(defs, def) } } for i, def := range defs { adv := models.Advisory{} err = driver.Model(&def).Related(&adv, "Advisory").Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } cves := []models.Cve{} err = driver.Model(&adv).Related(&cves, "Cves").Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } adv.Cves = cves bugs := []models.Bugzilla{} err = driver.Model(&adv).Related(&bugs, "Bugzillas").Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } adv.Bugzillas = bugs cpes := []models.Cpe{} err = driver.Model(&adv).Related(&cpes, "AffectedCPEList").Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } adv.AffectedCPEList = cpes defs[i].Advisory = adv packs := []models.Package{} err = driver.Model(&def).Related(&packs, "AffectedPacks").Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } defs[i].AffectedPacks = filterByMajor(packs, osVer) refs := []models.Reference{} err = driver.Model(&def).Related(&refs, "References").Error if err != nil && err != gorm.ErrRecordNotFound { return nil, err } defs[i].References = refs } return defs, nil }
なになに、パッケージネームからディフィニッション(数字)をデータベースから取ってきて、そのディフィニッションからcveを取って来る。あ、パッケージ名に対するcveが影響するバージョンを取ってくる(def.AffectedPacks)。データベース操作がいまいち読めないから、間違ってそうだが、大筋そうだろう。絶対間違ってるけど。
これで比較する準備ができたので、vulsのisOvalDefAffected()で現在のバージョンとOVALで取ってきたバージョンを比較すればよくて。lessThan関数でgithub.com/knqyf263/go-deb-versionライブラリを使って、比較する。これで、検知が可能
と言うことで、初めの予想と同じで、バージョンとcveが一対一やら、なんやかんやになってる。それはgoval-dictionaryがやってくれているんだろうけど、わからない。今度、そこ読んでみるかと。
感想としては、バージョンごとにcveやらを持っていて、それで全部比較するとなると、すごい計算量になりそう。。。
ま、私は、vulsをこれぜ完全理解したつもりです。
vuls何もわからない......
この記事は10分で書いたので、適当です。何か、間違いや、指摘があったら、教えてほしいです。
あと、こんな記事もあります。
Vulsのコードを読む その4 Vuls reportを調べてみた - Security Index
こちらの記事は、cpeから、cveを検知する話になってます。