starts_with() プレフィックスチェックのバイパスNotepad++ — session.xml の backupFilePath トラバーサルによる任意ファイル読み取り
PowerEditor/src/Notepad_plus.cpp (セッション復元 — backupFilePath 検証)session.xml への書き込みアクセス)Notepad++ はセッション復元時に、std::wstring::starts_with() による生の文字列プレフィックス比較を使って backupFilePath 属性を検証しますが、その前にパスを正規化しません。正規のバックアップディレクトリプレフィックスで始まりながらも ..\ トラバーサルシーケンスを含む巧妙に細工されたパスはチェックを通過し、OS がファイルを開くときには任意の場所に解決されます — 読み取り可能な任意のファイルの内容がエディタタブに読み込まれます。
スナップショット(バックアップ)モードを有効にして起動すると、Notepad++ は session.xml から前回のセッションを復元します。各エントリの backupFilePath は、アプリケーションのバックアップディレクトリ配下にあることが期待されます。整合性ゲートは、保存されたパスが期待されるバックアップディレクトリ文字列で始まることだけをチェックします。この比較は生の正規化されていない文字列に対して行われるため、攻撃者は正規のプレフィックスを先頭に付加し、..\ シーケンスでディレクトリの外へ移動できます。
チェックはテキスト上のプレフィックスを検査しますが、使用時には OS が解決したパスが開かれます。..\ が存在すると、この2つは一致しなくなります。
| 操作 | 対象 | 挙動 |
|---|---|---|
| チェック | 生の backupFilePath 文字列 | starts_with(backupDir) — プレフィックス一致で通過 |
| 使用 | OS 解決後のパス | ..\ シーケンスが任意の場所に畳み込まれる |
前提条件: session.xml への書き込みアクセス、スナップショット/バックアップモードが有効であること。
手順:
session.xml を上書きし、細工した backupFilePath を注入する:
<backupDir>\..\..\..\..\Users\victim\.ssh\id_rsa<backupDir>\ が starts_with() を満たすため、検証を通過する。..\ シーケンスを畳み込み、対象ファイルが開かれる。結果: 読み取り専用の窃取 — SSH 鍵、環境設定ファイル、資格情報ストアなどの機密ファイルを含め、対象ファイルの内容がエディタに表示される。
.env / 設定ファイル、資格情報ストア — ユーザーが読み取れる任意のファイル要件:
session.xml への書き込みアクセスbackupFilePath ペイロード: バックアップディレクトリプレフィックス + ..\ トラバーサルシーケンス + 対象ファイルのパス細工したパスを注入してアプリケーションを起動すると、対象ファイルがエディタタブに読み込まれます。
修正 (コミット 7e66f36) では、検証前に適切なパス正規化が行われるため、プレフィックス比較の前に ..\ シーケンスが畳み込まれます — チェックされるパスと使用されるパスが一致するようになります。