Windows Vulnerability Scan
こんにちは,普段はOSSのVulsへContributeしているMaineK00nです.
今回は,Windowsに潜む脆弱性をどのようにして検知するのかについて解説していきたいと思います.
Windows Updateについて
Windows Updateは累積更新という仕組みとなっており,
最新の更新プログラムを適用すると,最新の更新プログラムが包含する過去の未適用な更新プログラムまで適用されるようになっています.
また,各更新プログラムには,Microsoftが提供するサポート情報(KB; Knowlge Base)がリンクされており,それぞれの更新プログラムをKBIDで識別することができます.
以下の画像に示した更新プログラム(KB5010351)について見てみます.この更新プログラムは、次の更新プログラムを置き換えます:という部分に注目すると,画像の更新プログラム(KB5010351)を適用したとき,{KB5007266, KB5008218, KB5009557, KB5010196, …}の更新プログラムまで適用されるということを示しています.
また,この更新プログラムは、次の更新プログラムで置き換えられました:という部分からは,画像の更新プログラム(KB5010351)を含む,より最新な更新プログラム(KB5010427)が公開されていることが分かります.![]()
後述する脆弱性検知の中で,どの更新プログラムが未適用か判断するために,この置き換え情報が非常に重要となります.
更新プログラムの置き換え情報をどうやって集めるのか?
現在は,CVRFやMicrosoft Security Bulletin Dataにある情報から更新プログラムの置き換え情報を得ています.
ちなみに,CVRFやMicrosoft Security Bulletin Dataなどでは,置き換える更新プログラムを示すKBIDと置き換えられる更新プログラムを示すKBIDをノードとしたとき,それらを結ぶエッジが提供されているため,ある更新プログラムが置き換えるすべての更新プログラムを求めるには,エッジを辿りノードを整理することが必要です.
脆弱性情報の取得
Windowsの脆弱性情報は,CVRFフォーマットで月毎に分割されて提供されています.
例えば,2022年2月の脆弱性情報を取得する場合,次のリクエストによって取得できます.
1
|
$ curl -X GET --header 'Accept: application/xml' 'https://api.msrc.microsoft.com/cvrf/v2.0/cvrf/2022-Feb'
|
ref: https://api.msrc.microsoft.com/cvrf/v2.0/swagger/index
それでは,取得した2022年2月の脆弱性情報から,CVE-2022-22715についての定義を見てみます.(一部省略しています)
影響のあるプロダクトに対して,それぞれCVSSスコアやSeverityなどが記述されています.
脆弱性検知に使用する部分は,Remediationに記述されています.
Descriptionにはこの脆弱性を修正する更新プログラムのKBIDが記述されていて,この場合はKB5010351です.
また,この更新プログラム(KB5010351)によって置き換えられる更新プログラムはSupercedenceに記述されていて,更新プログラム(KB5009557)を置き換えることが分かります.
1 |
<prod:ProductTree> |
脆弱性検知の方針
CVRFのデータを見ると,CVE-IDに対して,更新プログラムのKBIDやProduct IDが結びついていることが分かりました.
Product IDだけでは,バージョン情報がなく,比較ができないため,Product IDからの検知は難しそうです.
今回は,修正されていない脆弱性を探すので,未適用な更新プログラムのKBIDを求め,そのKBIDに紐づくCVE-IDを求めることにします.
未適用な更新プログラムのKBIDを求める
では,未適用な更新プログラムのKBIDを求める方法について考えます.
PowerShellでWindows APIを使うと,次のようにして求められます.
この場合では,TitleよりKB5011267が未適用だと分かりました.(Title以外にもKBArticleIDsでも調べることができます)
1 |
PS C:\Windows\system32> $Session = New-Object -ComObject Microsoft.Update.Session |
ref: https://docs.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesearcher-search
しかし,この方法によって得られる未適用な更新プログラムは,コマンド実行時における最新の未適用な更新プログラムのみが表示されるようです.
最新の更新プログラムによって置き換えられた過去の未適用な更新プログラムについては表示されないため,
脆弱性スキャナを実装する上では,スキャン実行時のタイミングによって,
ある更新プログラムが表示されず,その更新プログラムのKBIDに紐づくCVE-IDを検出することができないという問題があります.
この問題を解決するために,更新プログラムの置き換え情報を使って,すべての未適用な更新プログラムを得る必要があります.
更新プログラムの置き換え情報から,どの更新プログラムによって置き換えられ,どの更新プログラムを置き換えたかということは分かるので,
どこまでの更新プログラムが適用済みかということが分かれば,すべての未適用な更新プログラムは取得できそうです.
先程,最新の未適用な更新プログラムを求める方法で紹介したものを少し変更して,適用済みの更新プログラムを取得してみます.
実行結果より,KB3193497が適用済みであることが分かりました.
1 |
PS C:\Windows\system32> $Session = New-Object -ComObject Microsoft.Update.Session |
しかしながら,私達の調査の中で,以下の画像のように,設定 > 更新とセキュリティ > Windows Update > の更新履歴を表示するの画面で適用済みの更新プログラムを確認すると,上記の検索では取得できていない更新プログラムがあることが分かりました.

これらを回避するために,Windows Updateの履歴からも適用済み更新プログラムを取得するようにします.
1 |
PS C:\Windows\system32> $Session = New-Object -ComObject Microsoft.Update.Session |
ref: https://docs.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesearcher-queryhistory
おまけ: 適用済み更新プログラムのKBIDを取得するその他の方法
適用済み更新プログラムのKBIDを調べる方法は他にもこのような方法があります.
- コントロールパネル > プログラム > プログラムと機能 > インストールされた更新プログラム
- コマンドプロンプト systeminfo
- PowerShell Get-HotFix (ref: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-hotfix?view=powershell-7.2)
- (Get-ComputerInfo).OsHotFixes (ref: https://docs.microsoft.com/en-us/dotnet/api/microsoft.powershell.commands.computerinfo.oshotfixes?view=powershellsdk-1.1.0)
- wmic qfe list
- コマンドプロンプト dism /online /get-packages より,Package_for_KB\d{6,7}にマッチするもの
- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages 内の KB\d{6,7} にマッチするもの
すべての未適用な更新プログラムのKBIDを求めるために
ここまでを整理すると,Windows APIを使って,適用済み更新プログラムのKBIDと最新の未適用な更新プログラムのKBIDが取得できました.
さらに,更新プログラムの置き換え情報が分かるので,すべての未適用な更新プログラムのKBID(以下の画像の表示されない未適用KBIDと表示される未適用KBID,より最新な未適用KBID)を取得できそうです.
ここで,問題となるのは表示されない未適用KBIDをどのように取得するかです.

1つは,適用済みKBIDの外側へ探索する方法と,もう1つは表示される未適用KBIDの内側へ探索する方法です.
前者の場合,すべての適用済みKBIDが取得できていない場合,もしくは適用済みKBIDがない場合には表示されない未適用KBID部分の取得が不完全になります.
後者の場合,ある表示される未適用KBIDに対する適用済みKBIDの取得が完全でない場合は,適用済みKBID部分が過検知されます.
今回は,過検知のリスクを考え,前者の方法で表示されない未適用KBIDを取得することにしています.
表示される未適用KBIDの内側へ探索する方法はなぜ難しい?
なぜ,表示される未適用KBIDの内側へ探索する方法が難しいかという点について,以下に示すKB4480056の置き換え情報を見ながら,考えます.
例えば,表示される未適用KBIDとして{KB5009823, KB5010580},適用済みKBIDとして{KB4598499}が与えられる場合を仮定します.
この場合では,表示されない未適用KBIDは{KB5009718, KB5007298, KB5006765, KB5004870, KB5004228, KB5003778, KB5001879, KB4601887}となります.
そして,取得漏れした適用済みKBIDに{KB5007298}があるとすると,表示されない未適用KBIDは{KB5009718, KB4601887}となります.
つまり,取得漏れがある場合,{KB5007298, KB5006765, KB5004870, KB5004228, KB5003778, KB5001879}に紐づくCVE-IDを過検知してしまうことになります.
適用済みKBIDがすべて正確に取得できていることを保証することは難しいことと,
後述するKBの置き換え情報を完全に取得することが難しいことから,内側へと探索する方法は過検知のリスクが大きいと判断しています.

FutureVulsでは前者の対策として
前者の適用済みKBIDや表示されない未適用KBIDが完全に取得できない場合に備えて,FutureVulsの画面上からKBIDを登録できるように対応しました.

仕上げ
これまでに,Windows APIの結果と更新プログラムの置き換え情報からすべての未適用な更新プログラムのKBIDを取得できました.
最後に,それらのKBIDに紐づくCVE-IDを求めることで,Windowsに潜む脆弱性が検知できます.
まとめ
この記事では,Windowsにおける脆弱性検知として,更新プログラム(KBID)の情報を使った手法を紹介しました.
これからもFutureVulsが正確な脆弱性検知を提供できるようにContributionしていきます.