同じ脆弱性情報を使っているはずなのに!?なぜか発生した脆弱性の検知漏れ:パッケージの分類がもたらした落とし穴

NTTドコモビジネスが開発しているSBOM管理ソリューション「Threatconnectome」において、Trivyと同じ脆弱性データベースを使用しているにもかかわらず、特定のパッケージで脆弱性検出漏れが発生した事例を紹介します。

はじめに

こんにちは。イノベーションセンターMetemcyberプロジェクトの千坂知也と申します。

本記事では、私たちMetemcyberプロジェクトが開発しているSBOM(Software Bill of Materials)*1管理ソリューション「Threatconnectome」(以下Tc)*2にて発生した大規模な脆弱性の検出漏れについて、その原因と対応、改善結果を取り上げます。

Tcでは、オープンソースの脆弱性スキャナTrivyが脆弱性情報として利用しているTrivy DBを利用しています。そんな中、Ubuntuのパッケージをスキャンした際、Trivyでは該当パッケージ内の脆弱性が検知された一方で、Tcでは該当パッケージ内の脆弱性を検知できていないことが発覚しました。

同じ脆弱性情報を利用しているはずなのになぜこのようなことが起きてしまったのか?私たちは、TrivyとTcの間で脆弱性マッチングの処理に何らかの違いがあると推測いたしました。

以降では、次の4つについて述べていきたいと思います。

  1. Trivyにおけるパッケージの分類について
  2. Trivyの脆弱性マッチングとTcの脆弱性マッチングの差異について
  3. Threatconnectomeにおける脆弱性の未検知問題の詳細
  4. プロジェクトでの対応策

1. Trivyにおけるパッケージの分類について

オープンソースの脆弱性スキャナTrivy*3では、コンテナイメージやファイルシステム、ソースコードなどに含まれる脆弱性や設定ミスを検出します[1]。CI/CDパイプラインへの統合が容易であり、SBOM生成・ライセンススキャンなども活用できることからセキュリティ管理の幅広い領域で使われています。このTrivyでは、脆弱性スキャンの対象を大まかに以下の2種類に分けて扱います[2]

  • OSパッケージ:Linuxディストリビューションのパッケージマネージャで管理されるパッケージ(dpkg,apt, rpm, apk など)
  • Langパッケージ:各プログラミング言語の依存ライブラリ
    (pip, npm, gem, go, maven など)

このうちOSパッケージは、さらに手元でインストールするファイル群及びそれらのファイル群のインストール/アンインストールを制御するパッケージと元のソースが書かれたパッケージの2種類が存在します。Ubuntu(Debian系)のOSパッケージでは前者をBinary Package(バイナリパッケージ)、後者をSource Package(ソースパッケージ)と言います。次の章ではこのバイナリパッケージとソースパッケージを説明していきます[3]

バイナリパッケージとソースパッケージについて

公式Ubuntu documentationのPackage modelの項では、ソースパッケージ→バイナリパッケージの順で記載がありますが、ここでは分かりやすさを重視してバイナリパッケージから説明をさせていただきたいと思います[4]

バイナリパッケージ

バイナリパッケージとは、パッケージマネージャが理解できる標準化された形式のパッケージのことです[5]。Debian系のバイナリパッケージは、.debというファイル拡張子を持ち、次の2種類のファイル群を含みます。

  • 対象システムにインストールされる実際のファイル群
  • それらのファイルをどのようにインストールまたはアンインストールするかを制御するファイル群

これにより、ソフトウェアを対象のマシンに簡単に配布・インストール・アンインストールできるようになります。

ソースパッケージ

ソースパッケージは、複数のバイナリパッケージをビルドするためのソースコードおよびビルド情報を含んだものです[6]。その構成は次の通りです。

  • Debianソースコントロール(.dsc)ファイル
  • 1つ以上の圧縮されたtarファイル(.tar.gz, .tar.xz など)
  • パッケージの形式に応じて、追加のファイル

特に.dscファイルには、以下のようなメタデータが含まれます。

  • ファイルのリスト
  • パッケージ名とバージョン
  • 作成されるバイナリパッケージの一覧
  • 依存関係
  • デジタル署名
  • その他多数のフィールド

つまり、普段我々が手元でインストールするファイル群以外に元のソースを含んだパッケージも別に存在しているということです。そもそもなぜこのような分類をしているのでしょうか?

バイナリパッケージとソースパッケージの分類の意図

Ubuntu(および Debian 系)は、基本的にDebianのパッケージモデル(パッケージ方式)を採用しており、上述した通り「ソースパッケージ」→(ビルド)→「バイナリパッケージ」という流れが基本となります。

このような分類をしている理由の1つとして「同じソースから、異なるアーキテクチャやOS向けへとビルドできるようにするため*4」があります[7]。Debian系では、まず1つのソースパッケージが用意され、これをもとに複数のバイナリパッケージがビルドされます。実際にソフトウェアを使う環境はさまざまで、CPUの種類(アーキテクチャ)も異なります。UbuntuやDebian系でよく使われるアーキテクチャの具体例としては、amd64、arm64、i386などがあります。個別に各CPUアーキテクチャやOS環境向けのパッケージを用意するのではなく、大本のソースパッケージからそれぞれの環境へ適した最適な実行バイナリを生成するほうが、運用面で効率的です[8]

それ以外にもビルドの再現性を担保するため(ソースからバイナリを再ビルドして、元のバイナリと一致するか確認できる。改ざん検出やセキュリティ検証に不可欠)、パッチ管理を容易にするため(Debian系では、オリジナル開発元のソースに対し、独自パッチを追加して管理する)などもソースパッケージとバイナリパッケージを分ける利点として挙げられます。

Trivyにおける脆弱性検出の仕組み

Trivyでは、OSパッケージとLangパッケージをそれぞれ独立して識別・スキャンし、対応する脆弱性データベースとマッチングします。この二層構造により、インフラ層(OS)とアプリケーション層(言語ライブラリ)の両面に潜むセキュリティリスクを網羅的に検出できる点が、Trivyの大きな強みです。

このマッチングに利用する脆弱性データベース(Trivy DB)では、OSパッケージにおいてソースパッケージ名を基準に脆弱性情報を管理しています[9]。その理由はUbuntuやDebian系ディストリビューションの脆弱性情報が基本的にソースパッケージ単位で配布されているためです[10][11]。そのため、マッチングに利用する脆弱性情報(今回の場合Trivy DB内の情報)もソースパッケージ名で格納しておかないと、マッチングすることが出来ないのです。

この仕組みによって、同一のソースパッケージからビルドされた複数のバイナリパッケージに対しても、一貫した脆弱性判定が可能となっています。

Threatconnectomeにおける脆弱性の未検知問題の詳細

冒頭でも申し上げたとおり、私たちが開発しているSBOM管理ソリューションTcにおいて、Ubuntuのパッケージに関する脆弱性検出漏れが発生しました。Tcは脆弱性情報としてTrivy DBを利用していますが、linux-modules-5.15.0-1025-gcpというパッケージを含むソフトウェアをスキャンした際、Trivyではパッケージ内の脆弱性が検知された一方で、Tc側では同一パッケージ内の脆弱性が検知できていなかったのです。

調査の結果、Tcでは入力されたSBOMファイルのバイナリパッケージ名とエコシステムのみを脆弱性マッチングのキーとして使用していたことが原因であると分かりました。

下記は実際に我々が入力したSBOMファイル(フォーマット:CycloneDX)の一部(コンポーネントのひとつ)になります。この例では"name"がバイナリパッケージ名、"aquasecurity:trivy:SrcName"がソースパッケージ名に該当します。この場合、"linux-gcp-5.15"がソースパッケージ名です。 前述したとおりUbuntu(Debian系)の脆弱性情報はソースパッケージ名で配布されているため、Trivy DBではOSパッケージの脆弱性情報をソースパッケージ名(この場合linux-gcp-5.15)で管理しており、Trivy自体も入力されたSBOMの"aquasecurity:trivy:SrcName"部分を抽出しマッチングを行います。


{
  "name": "linux-modules-5.15.0-1025-gcp",
  "purl": "pkg:deb/ubuntu/[email protected]~20.04.2?arch=amd64&distro=ubuntu-20.04",
  "properties": [
    {
      "name": "aquasecurity:trivy:PkgType",
      "value": "ubuntu"
    },
    {
      "name": "aquasecurity:trivy:SrcName",
      "value": "linux-gcp-5.15"
    },
    …
  ],
  …
}

Tcは、Trivy DBの脆弱性情報を利用していたものの、入力されたSBOMから抽出したバイナリパッケージ名(linux-modules-5.15.0-1025-gcp)とpurlフィールドなどから構築されるエコシステムのみを使用していたため、Trivy DB内にあるソースパッケージ名(linux-gcp-5.15)と一致せず、脆弱性を検出できない問題が発生したということです。

適切な脆弱性情報は(Trivyと同じ脆弱性情報を利用していたため)あったものの、入力されたSBOMから抽出するフィールドが異なっていたということです。

SBOM内の"aquasecurity:trivy:PkgType"がubuntuであることから、このパッケージはUbuntuのOSパッケージであると判別できます。しかし、OSパッケージ特有のSrcNameを正確に処理するロジックが不足していたわけです。

プロジェクトでの対応策

前章で述べた通り、Tcでは脆弱性マッチングの際に入力されたSBOMのバイナリパッケージ名を使用していたことが原因で、ソースパッケージ名ベースで管理されているTrivy DBの脆弱性情報と一致せず、一部の脆弱性を検出できていませんでした。この問題を受け、我々のプロジェクトでは以下の対応を実施しました。

  • OSパッケージとLangパッケージの区別を明確化
  • 入力されたSBOMに含まれる脆弱性を解析する際に、OSパッケージとLangパッケージを明確に区別して扱うようにし、OSパッケージの場合であれば、入力されたSBOMの「ソースパッケージ名」と「バイナリパッケージ名」の両方を保持するよう仕様を変更しました。

  • パッケージの一意識別ロジックを拡張
  • パッケージを一意に識別するための条件を、従来の「バイナリ名+エコシステム」から次のように拡張しました。

    一意識別キー:(エコシステム, バイナリパッケージ名, ソースパッケージ名)

  • 脆弱性マッチング条件の改善
  • 脆弱性データベースとのマッチング条件を次のように変更しました。

    マッチング条件: 「エコシステムが同一」かつ(「バイナリパッケージ名が一致」または「ソースパッケージ名が一致」)

    さらに、バイナリパッケージ名、ソースパッケージ名両方の一致候補が存在する場合には、ソースパッケージ名一致を優先するルールを設けることで、判定の一貫性と精度を確保しました。

    実施後の効果

    これらの対応により、バイナリパッケージ名、ソースパッケージ名の両方でマッチング可能になり、脆弱性の検知精度が大幅に向上しました。

    linux-gcp-5.15パッケージの脆弱性に限ってみれば3191件もの脆弱性が新しく検知されるようになりました(2025/7/2時点)。逆にいうと、本対応以前までlinux-gcp-5.15パッケージに関するものだけでも3191件もの脆弱性を見落としていたということになります。

    まとめ

    本稿では、OSパッケージの分類による差分から発生する脆弱性の未検知問題について取り扱いました。SBOMなどを用いたソフトウェア内のパッケージ単位での脆弱性管理は求められつつある一方で、その管理の困難性や一貫したアプローチ法がないなどの課題もあります。我々Metemcyberプロジェクトでは、Trivyを踏襲しつつ、独自のモデル設計によりこれらの問題の解決を図ってきました。ご興味がある方はぜひThreatconnectome の GitHubページなどもご覧ください。ご連絡お待ちしております。

    脚注

    1. ソフトウェアを構成するコンポーネント(オープンソースソフトウェア、ライブラリなど)の一覧表(リスト)。ソフトウェアのBOM。各コンポーネントの名称、バージョン、依存関係、ライセンス情報などが含まれる。代表的なSBOM生成ツールにTrivy、Black Duck、Syftなどがあり、代表的なSBOMフォーマットにCycloneDX、SPDXなどがある。
    2. nttcom/threatconnectome
    3. Trivy
    4. 全てのアーキテクチャに対応しているわけではない。ビルド依存関係によっては対応していないアーキテクチャもある。

    参考文献

    1. Vulnerability - Trivy
    2. Container Image - Trivy
    3. Package model - Ubuntu documentation
    4. Package format - Ubuntu project documentation
    5. 3. Binary packages — Debian Policy Manual v4.7.2.0
    6. 4. Source packages — Debian Policy Manual v4.7.2.0
    7. Debian Policy Manual
    8. 5.3. Structure of a Source Package
    9. Ubuntu vulnerability source - Trivy DB
    10. Debian Policy Manual v4.7.0.1
    11. ubuntu-cve-tracker