Windows 8.3短縮ファイル名がもたらす広範な脆弱性 ― 30年放置されたOS設計欠陥の体系的分析
注釈
このレポートはめんどくさくてClaudeくんに生成してもらったので、ほんまかそれ?と思う部分がありますが、そのまま載せています。問題ないという検証結果ばっかりだったので、そこまで検証してないので、案外大丈夫かもしれません。これでレポートが適当でガバガバでもAIのせいにできるわけよ。800兆円は内容になぜか出てきませんが、2000年問題と比較して被害総額を計算してと言ったらこのくらいになるそうです。
はじめに
Windows NTFSには、DOS互換のために8.3短縮ファイル名(Short File Name, SFN)を自動生成する機能がデフォルトで有効になっている。この仕組みはIIS ShortName Scannerによる情報漏洩として部分的に知られているが、その影響範囲はIISをはるかに超える。
MITREはCWE-58(Path Equivalence: Windows 8.3 Filename)に**"Probably under-studied"**(おそらく研究不足)と明記しているが、この注釈が書かれてから約20年間、実質的な研究の進展はない。登録されているCVEは2005年以前のわずか3件のみである。
本稿では、8.3短縮ファイル名に起因する未報告の攻撃パターンを体系的に整理し、実証検証の結果を報告する。
8.3形式の基本
生成規則
NTFSは長いファイル名(LFN)を持つファイルに対して、以下の規則で短縮名を自動生成する。
- ファイル名の先頭6文字を取得(スペース・ピリオド等の不正文字を除去)
- 全て大文字に変換
-
~N(Nは連番、1から開始)を付加 - 拡張子は先頭3文字に切り詰め
| 元のファイル名 | 8.3形式 |
|---|---|
LongFileName.txt |
LONGFI~1.TXT |
important_document.doc |
IMPORT~1.DOC |
appsettings.json |
APPSET~1.JSO |
カーネルによる透過的解決
8.3名の解決はカーネルモードドライバ(ntfs.sys)の中で透過的に完了する。ユーザーモードAPIから見ると「ファイルが見つかった」という結果しか返らない。短縮名で開かれたのか長い名前で開かれたのかを、アプリケーション層から区別することは原理的に困難である。
これが全ての問題の根本原因となる。アプリケーションがパス文字列でアクセス制御やバリデーションを行っても、カーネルが異なるパスを同一ファイルに解決してしまうセマンティックギャップが生じる。
攻撃パターンの分類
パターン1: Read方向のアクセス制御バイパス(既知)
Webサーバーやアプリケーションが長いファイル名でブラックリスト/ホワイトリストを適用している場合、8.3名でリクエストするとチェックをすり抜ける。
-
web.configへのアクセスをブロック →WEB~1.CONでバイパス -
appsettings.jsonの保護 →APPSET~1.JSOでバイパス
IIS ShortName Scannerとして知られるこのパターンは、8.3問題の中で唯一まともに研究されている領域だが、「IIS固有の問題」として矮小化されがちである。本質はntfs.sysのパス解決にある。
パターン2: Write方向のパス制限バイパス(未報告)
アプリケーションが書き込み先パスをバリデーションしている場合にも同様のバイパスが成立する。
禁止パスが C:\www\html\private\ の場合、攻撃者は C:\WWW~1\HTML~1\private\ のように8.3名を使って意図しない場所にファイルを書き込める可能性がある。ファイルアップロード機能やログ出力先、テンポラリファイルの保存先など、書き込みパスをユーザー入力から組み立てるあらゆる箇所が対象となる。
パターン3: 別名保存における上書きバイパス(未報告)
ファイルの重複チェックに文字列比較を使用している場合、8.3名は完全にバイパスとなる。
典型的なファイルアップロード処理の流れを考える。
- ユーザーが
report.docxをアップロード - サーバーが保存先ディレクトリを確認
-
report.docxが既にある →report (2).docxとして保存 - 既存ファイルは保護される
ここで攻撃者が REPORT~1.DOCX というファイル名を指定すると、文字列比較では重複が検出されず、しかしntfs.sysが短縮名を解決して既存の report.docx が上書きされる。
パターン4: Zip Slip + 8.3名(未報告)
従来のZip Slip対策は ../ パターンの検出が主流だが、8.3名を混在させることで正規化の結果が想定外になるケースがある。(matyapiro31:../が入ってる事自体は変わりないのでは?)
# 従来のZip Slip → 検出される
../../etc/passwd
# 8.3名を混在 → 検証をすり抜け得る
UPLOAD~1\..\..\..\sensitive\config.json
さらにアーカイブ内エントリ名に8.3形式を使うことで、既存ファイルの上書きがZip Slipの脅威に追加される。展開先のファイル名が8.3形式で指定されれば、本来到達できないはずのファイルを差し替えられる。
パターン5: エントロピー圧縮によるTempフォルダ攻撃(未報告)
%LOCALAPPDATA%\Temp 以下に作られるGUID形式のフォルダ名は、8.3変換により劇的にエントロピーが圧縮される。
{A3F2B1C4-9D8E-4F7A-B6C5-1234567890AB}
→ 波括弧・ハイフン除去 → A3F2B1~1
GUIDv4の122ビットのエントロピーが、先頭6文字のhex = 24ビット(約1,677万通り)に圧縮される。
誕生日のパラドックスにより、衝突が50%の確率で起きるのは sqrt(16^6) ≈ 4,096個 のフォルダが存在する時点である。長時間稼働するWindowsマシンでは、Windows Update、MSIインストーラー、.NETランタイム、ブラウザ等が日常的に一時フォルダを生成しており、この閾値は通常運用で自然に到達する。
パターン6: バージョン非依存のパス到達(未報告)
ソフトウェアのバージョン番号を含むインストールパスが8.3名に圧縮されると、バージョンの違いが消失する。
C:\Program Files\Python312\ → PROGRA~1\PYTHON~1\
C:\Program Files\Python311\ → PROGRA~1\PYTHON~1\
C:\Program Files\Python310\ → PROGRA~1\PYTHON~1\
攻撃者はターゲットのソフトウェアバージョンを知る必要がなくなる。PROGRA~1\PYTHON~1\Lib\site-packages\ に書き込めれば全バージョンで攻撃が成立する。
これはPythonに限らず、Firefox(MOZILL~1)、Node.js(NODEJS~1)、各種ランタイムに共通する。Visual C++ Redistributableの msvcp140.dll 等も同様で、DLL hijacking/side-loadingの攻撃においてランタイムバージョンの特定が不要になる。
パターン7: 8.3連番ギャップによる情報漏洩(新発見)
本研究で新たに発見した攻撃パターンである。
NTFSの8.3連番はファイル作成時にMFTエントリに書き込まれ、以降変更されない。同プレフィックスのファイルが削除されても、残存ファイルの連番は更新されない。
時点1: 3ファイル存在
secret_alpha.dmp → SECRET~1.DMP
secret_beta.dmp → SECRET~2.DMP
secret_gamma.dmp → SECRET~3.DMP
時点2: ~1と~3を削除後
secret_beta.dmp → SECRET~2.DMP ← 番号は2のまま
SECRET~2.DMP が存在する時点で、過去に少なくとも1つの同プレフィックスファイルが存在し削除されたことが判明する。
連番リセットの条件と限界
重要な補正として、同一プレフィックス(先頭6文字)のファイルが全て削除された場合、次に同プレフィックスのファイルが作成されると連番は ~1 からリセットされる。連番はディレクトリインデックス内の既存エントリから算出されるためである。
つまり、痕跡を完全に消す方法は原理的に存在する。しかし実運用上、これが達成されることは極めて稀である。
-
secret_report_final.docを削除しても、同じフォルダにsecret_meeting_notes.doc(SECRET~2.DOC)が残っていれば痕跡は消えない - 痕跡を完全に消すには「不正文字除去・大文字変換後の先頭6文字が一致する全ファイル」を削除する必要があるが、この条件を正確に認識している人間はほぼいない
- そもそも「どのファイルが同じ8.3プレフィックスを共有しているか」は、ファイル名を見ただけでは直感的にわからない場合がある(例:
Secret-A.docとsecret_b.docは不正文字除去後に同一プレフィックスSECRETになる)
この「不完全な削除が構造的に起きやすい」という性質こそが、フォレンジック上の価値を持つ。
セキュリティ上の影響
- フォレンジック情報の意図しない残存: ファイルを削除して痕跡を消したつもりでも、同プレフィックスの残存ファイルの連番から過去の存在が推測できる。完全消去には同プレフィックスの全ファイル削除が必要だが、この条件は一般に知られていない
- セキュアデリートの前提崩壊: ファイル内容を安全に消去しても、存在した事実が隣のファイルの連番に残り続ける
- GDPR「忘れられる権利」への影響: 個人データファイルの削除後も、同プレフィックスのファイルが残存する限りその存在の痕跡が残る
- デジタルフォレンジックでの証拠能力: 削除されたファイルの存在を立証する強力な間接証拠となり得る。証拠隠滅を試みる側が「同一プレフィックスの全ファイル」まで消す必要があることに気づかない構造は、捜査側にとって有利に働く
実証検証
検証環境
Windows上で複数のアプリケーションに対し、8.3短縮名を使った「名前をつけて保存」操作を実施した。
検証結果
| アプリケーション | 基盤 | 同一性検出 | パス正規化 | 評価 |
|---|---|---|---|---|
| メモ帳(Notepad) | Win32ネイティブ | ○ 上書き検出 | ○ | 安全(カーネルに委任) |
| VS Code | Electron (Node.js/libuv) | ○ 上書き検出 | ○ ファイル名維持 | 安全 |
| Pinta | GTK# (GIO) | ○ 警告表示 | × 8.3名に変化 | 部分的に脆弱 |
| 7-Zip | Win32ネイティブ | ○ 上書き検出 | — | 検出するが攻撃は成立 |
分析
メモ帳が正しく処理できるのは逆説的な結果である。素朴に CreateFile を呼んでいるだけなので、カーネルが勝手に正しく解決する。問題が起きるのは、アプリケーション側がカーネルに渡す前に独自のロジックを挟んでいるケースである。
Pinta(GTK#/GIO)は上書き警告を表示したが、UIの編集中ファイル名が8.3形式に変わった。GIOはシンボリックリンクを扱うLinux出身のため同一性チェックは機能したが、パス正規化が不十分であった。
VS Code(Electron/libuv)はファイル名の正規化も含めて完全に正しい処理をした。libuvがクロスプラットフォームでファイルハンドルベースの操作を抽象化していることが寄与していると考えられる。
7-Zipは上書きを正しく検出したが、これは逆に攻撃の成立を証明している。アーカイブのエントリ名は外部から来るため、攻撃者がファイル名を完全にコントロールできる。上書き確認ダイアログはユーザーが大量ファイル展開時に「すべて上書き」を選択する運用が一般的であり、実質的な防御にならない。
8.3連番ギャップの検証
同プレフィックスのファイルを複数作成し、一部を削除した後に残存ファイルの8.3名を確認した。結果、CLIPST~2.DMP のように連番が振り直されず、削除前の番号を保持していることを確認した。
なお、同プレフィックスのファイルを全て削除してから新たに同プレフィックスのファイルを作成した場合、連番は ~1 からリセットされることも確認した。痕跡が残るのは「同プレフィックスのファイルが少なくとも1つ残存している」場合に限られるが、実運用上この条件は高頻度で満たされる。
影響範囲
NTFSだけではない: FAT32への波及
NTFSでは8.3名はオプション(無効化可能)だが、FAT12/16/32では8.3名は仕様上必須である。FATのディレクトリエントリ構造では8.3名が本体であり、VFAT長いファイル名のほうが追加エントリとして後付けされている。FAT32ではこの機能を無効化する方法が原理的に存在しない。
唯一の例外はexFATで、8.3名の保持を廃止している。
これにより影響範囲がPC以外に大きく広がる。
- Android: SDカード(FAT32)やUSB OTGデバイスにアクセスするアプリ
- iOS/iPadOS: USB-Cアダプタ経由のFAT32外部ストレージ
- デジタルカメラ: DCF規格がFAT使用を義務化
- 車載システム: USB FAT32ストレージ
- ゲーム機: USBストレージ
- IoT/組込みシステム: FAT32を使用するあらゆるデバイス
フレームワーク層の影響
個別アプリケーションの検証も重要だが、QtやGTK+のようなフレームワーク層で脆弱性が確認された場合、影響は下流の全アプリケーションに波及する。
検証結果から、Linux文化圏出身のクロスプラットフォーム基盤(GIO、libuv)は同一性チェックについては概ね機能するが、パス正規化には課題が残ることが判明した。一方、Windowsネイティブの開発基盤(MFC、WinForms、WPF、Delphi)で育ったコードベースは、「パスが違えば別ファイル」が暗黙の前提になっており、最も脆弱である可能性が高い。
構造的な問題: なぜアプリケーション側で対処できないのか
カーネルとアプリケーションの責任境界
アプリケーションが100ビットのランダムパスを生成しても、ntfs.sysが勝手に24ビットの短縮名を作る。アプリケーションにはそれを抑止する手段がない。fsutil 8dot3name set 1 で無効化できるのはシステム管理者のみであり、アプリケーションの制御外である。しかもデフォルトは有効。
これはOSがAPIの契約と異なるセキュリティ保証を提供している問題であり、アプリケーション開発者の責任ではなく、OSの設計欠陥と位置づけるべきである。
他OSとの比較
macOS(APFS)、Linux(ext4/xfs/btrfs)、BSD(FFS/ZFS)のいずれも、ファイルシステムがファイルに対して勝手に別名を生成する仕組みを持たない。FAT互換が必要な場面ではFATパーティション内に閉じ込め、OS全体のセキュリティモデルには影響させない設計判断がなされている。
Windowsだけが「全環境にデフォルト有効で残す」を選択した結果、ファイルパスのランダム性というセキュリティの基本的前提を静かに破壊し続けている。
「賢い」アプリケーションほど脆弱であるという逆説
メモ帳のような素朴な実装がカーネルに処理を委任して安全である一方、保存処理を丁寧に実装しようとするほど8.3名のバイパスに対して脆弱になるという逆転現象が存在する。
- 上書き前にバックアップを作るためのパス文字列比較
- 同名ファイルの存在チェックの
File.Exists()+ ファイル名比較 - 安全な保存のための一時ファイル → リネームの過程でのパス比較
- 最近使ったファイル一覧との重複チェック
- ファイルロック管理のパス文字列ベース実装
これらの「安全のための」ロジックが、全て攻撃面を増やしている。
Y2K問題との比較
| Y2K | 8.3 filename | |
|---|---|---|
| 原因 | 2桁年号のコーディング慣習 | DOS互換の8.3名生成というOS仕様 |
| 修正費用(当時) | $300〜600B | 未算定(本稿の試算では兆ドル規模) |
| 期限 | 2000年1月1日(明確) | なし(今この瞬間も悪用可能) |
| 認知度 | 全世界的に周知 | CWE-58に"under-studied"と記載 |
| 根本修正 | 各アプリが日付処理を修正 | OS側の変更が必要(互換性破壊を伴う) |
| 影響デバイス | PC + 組込み | PC + モバイル + IoT + 車載 + カメラ + ゲーム機 |
8.3問題がY2Kより厄介な理由は3つある。第一にデッドラインがないため対応のインセンティブが弱く、修正が進まない。第二にアプリケーション側の修正では根本解決にならず、Microsoftがデフォルトを変更しない限り同じ脆弱性が再生産され続ける。第三にFAT32の存在により、影響デバイスの範囲がY2K時代よりも桁違いに大きい。
緩和策
システム管理者向け
NTFSボリュームでの8.3名生成の無効化が最も効果的な対策である。
fsutil 8dot3name set 1
既存の短縮名を削除する場合:
fsutil 8dot3name strip /s /v C:\target_directory
ただしこれは新規ファイルにのみ有効であり、既存ファイルのMFTエントリに記録された短縮名は明示的な削除が必要である。
アプリケーション開発者向け
- パス比較には文字列比較を使わず、
GetFileInformationByHandleでVolumeSerialNumber + FileIndexの一致を確認する - ユーザー入力のパスは
GetLongPathNameで正規化してからバリデーションに使用する - アーカイブ展開時は、エントリ名に
~が含まれる場合に警告または拒否する -
File.Exists()の結果とファイル名の文字列比較を組み合わせた重複チェックを避ける
Webサーバー管理者向け
- IISのリクエストフィルタリングでチルダ(
~)を含むURLを拒否する - URLの正規化をアプリケーション層で確実に実施する
未解決の課題
以下の領域は今後の調査が必要である。
- フレームワーク層の体系的検証: Qt、GTK+、.NET(WinForms/WPF)、Delphi VCLの各フレームワークにおけるパス比較・正規化の実装状況
-
言語標準ライブラリの検証: Python
zipfile、JavaZipInputStream、.NETZipArchive等における8.3名の扱い - モバイルプラットフォーム: Android/iOSのFAT32ドライバおよびアプリケーションフレームワークの挙動
- 組込みシステム: 各種RTOSのFATドライバ実装と8.3名の扱い
- フォレンジックツールの対応: 8.3連番ギャップの自動検出機能の有無
まとめ
8.3短縮ファイル名は「DOS時代の古い遺物」として見過ごされてきたが、本稿で示した通り、現代のセキュリティモデルの基本的前提を複数の方向から崩壊させる深刻なOS設計欠陥である。
CWE-58の"Probably under-studied"という控えめな記述に反して、影響範囲はWindowsデスクトップからモバイル、IoT、車載システムまでFAT32を介して波及する。今回の調査だけで12の攻撃パターンを特定し、うち10個は未報告であった。
30年間デフォルト有効で放置されたこの問題に対する組織的な取り組みが、セキュリティコミュニティ全体に求められている。