flawopen.com/Incidents/windows-update-stack-symlink-eop-september-2026
CVE-2026-81963:Windows Updateのリンク権限昇格
CVE-2026-81963はWindows Updateのリンク解決に関する悪用済みの欠陥です。影響バージョン、修正、サービスの安全なファイル処理を解説。[1], [2]
マスターキーを持つ夜間の管理人が、壁の矢印に従って「廊下の突き当たりの倉庫」へ荷物を届けますが、自分がどの部屋に入ったかは確認しません。入居者はその矢印を動かせます。ある入居者が倉庫を指す矢印を支配人室に向け、どの扉も開くマスターキーを持つ管理人は中へ入り、支配人の机に荷物を置きます。その扉を入居者自身は決して開けられません。管理人のキーが代わりに開けたのです。対策は、管理人が実際に開けた扉の番号を読み取り、入居者が動かせる矢印には従わないことです。[5], [9]
主要な概念と専門用語
Windows Update スタック- 更新プログラムのスキャン、ダウンロード、ステージング、インストールを担う Windows のコンポーネント群。更新の適用には OS の保護された領域への書き込みが必要なため、SYSTEM として動作します。[1]
SYSTEM(NT AUTHORITY\SYSTEM)- Windows サービスが動作する際のローカルアカウント。ローカルマシンでは管理者より強い権限を持ち、ファイル操作がほぼ拒否されません。[1]
ジャンクション / シンボリックリンク(再解析ポイント)- あるパスを別の場所へ解決させる NTFS のオブジェクト。標準ユーザーは自分が管理するフォルダーにジャンクションを作り、その名前を書き込めないディレクトリへ向けられます。[9]
リンク追跡(CWE-59)- プログラムが名前でファイルを開く・書き込む・移動する・削除する際、その名前が想定どおりの場所に解決するか確認しないため、他人が仕込んだリンクによって操作先がすり替わること。[5], [2]
FILE_FLAG_OPEN_REPARSE_POINT- CreateFileW のフラグで、パスの最後の要素が再解析ポイントの場合、そのリンクをたどらず再解析ポイント自体を開きます。このフラグだけでは、それ以前のパス要素にある再解析ポイントの処理は防げません。[6]
TOCTOU(CWE-367)- 検査時と使用時の差。検査とそれに依存する操作の間にファイルシステムが変化すること。パス文字列を検査してから名前で開くと、この隙が生まれます。[12]
フレームワーク対応
- このガイドで説明する弱点の CWE 参照: CWE-59 CWE-284
- CISA KEV — 追加日 2026-09-08 — CVE-2026-81963
インシデントのタイムライン
マイクロソフトが CVE-2026-81963 を予約する。[2]
9 月の Patch Tuesday:マイクロソフトが修正を公開し、この欠陥を「Exploitation Detected」かつ非公開扱いと表示する。[1]
CISA が CVE-2026-81963 を Known Exploited Vulnerabilities カタログに追加。米連邦機関の修正期限は 2026 年 9 月 22 日。[4]
マイクロソフトが勧告の改訂版を公開する。[1]
ステップ・バイ・ステップの攻撃フロー
SYSTEM のサービスがユーザーの変更できるパスで動作する
Update スタックのコンポーネントは SYSTEM として動作し、ステージング用や作業用のディレクトリでファイルを扱います。標準ユーザーがそのパス上のどこかでエントリを作成・削除・改名できれば、パスの解決先を決めるのはそのユーザーです。今回どのパスが影響を受けたかをマイクロソフトは明らかにしていません。[1]
ソースコード比較:脆弱 vs 堅牢化
Microsoft は影響を受けた関数やパッチを公開していません。この防御例は Microsoft のコードではありません。所有者だけを確認しても不十分です。オブジェクトの所有者であっても、DACL が一般ユーザーの書き込みを拒否するとは限りません。このパターンは、インストーラーが固定のステージングパスとすべての親ディレクトリを、SYSTEM と Administrators だけに書き込みを許可する明示的な DACL で作成することを前提とします。この関数は DACL を読み取ったり検証したりしません。インストーラーが事前に設定するアクセス許可は、展開時の前提条件です。開いたディレクトリハンドルを検証し、NtCreateFile と FILE_CREATE を使ってそのハンドルを基点に単一の子ファイル名を作成します。連結したパスを再度開くことはありません。サポート対象の環境で DACL とファイルシステムの動作を検証してください。CVE-2026-81963 の修正には Microsoft の更新プログラムを適用してください。[5], [6], [7], [8], [9], [10]
ソース抜粋: Windows のパス処理例。Microsoft のソースコードではありません
/* 説明用の例であり、Microsoft のソースコードではない。影響を受けた関数は公開されていない。SYSTEM で動作するサービスが、一般ユーザーから変更可能な
* staging ディレクトリに書き込む。
*/
BOOL WriteStagedFile(LPCWSTR stagingDir, LPCWSTR name,
const BYTE *data, DWORD size)
{
WCHAR path[MAX_PATH];
if (FAILED(StringCchPrintfW(path, MAX_PATH, L"%s\\%s", stagingDir, name)))
return FALSE;
/* CWE-59: CreateFileW はパスの各要素で junction とシンボリックリンクを解決し、アクセス確認には SYSTEM
* トークンを使う。ユーザーが stagingDir を junction に差し替えると、書き込み先もその対象に変わる。
*/
HANDLE h = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
return FALSE;
DWORD written = 0;
BOOL ok = WriteFile(h, data, size, &written, NULL) && written == size;
CloseHandle(h);
return ok;
}/* 防御パターンの例であり、Microsoft のソースコードやパッチではない。インストーラーはこのパスとすべての親ディレクトリを作成し、SYSTEM と
* Administrators だけに書き込みを許可する明示的な DACL を設定する必要がある。
*/
#include <windows.h>
#include <winternl.h>
static const WCHAR STAGING_DIR[] =
L"C:\\ProgramData\\Vendor\\Update\\Staging";
BOOL WriteStagedFile(LPCWSTR name, const BYTE *data, DWORD size)
{
if (name == NULL || data == NULL || name[0] == L'\0' ||
wcspbrk(name, L"\\/:") != NULL || wcscmp(name, L".") == 0 ||
wcscmp(name, L"..") == 0)
return FALSE;
/* ディレクトリオブジェクトを固定する。FILE_SHARE_DELETE を指定しないことで名前変更を防ぐ。 */
HANDLE dir = CreateFileW(STAGING_DIR,
FILE_LIST_DIRECTORY | FILE_TRAVERSE | FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OPEN_REPARSE_POINT,
NULL);
if (dir == INVALID_HANDLE_VALUE)
return FALSE;
FILE_ATTRIBUTE_TAG_INFO tag;
WCHAR actual[MAX_PATH];
BOOL ok = FALSE;
DWORD n;
if (!GetFileInformationByHandleEx(dir, FileAttributeTagInfo,
&tag, sizeof tag) ||
(tag.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
goto done;
n = GetFinalPathNameByHandleW(dir, actual, MAX_PATH,
FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
if (n == 0 || n >= MAX_PATH ||
_wcsicmp(actual, L"\\\\?\\C:\\ProgramData\\Vendor\\Update\\Staging") != 0)
goto done;
/* パスを再構築せず、このハンドルを基準に新しい子項目を開く。 */
size_t nameChars = wcslen(name);
if (nameChars == 0 || nameChars > 255)
goto done;
USHORT nameBytes = (USHORT)(nameChars * sizeof(WCHAR));
UNICODE_STRING relativeName = { nameBytes, nameBytes, (PWSTR)name };
OBJECT_ATTRIBUTES oa = {0};
oa.Length = sizeof oa;
oa.RootDirectory = dir;
oa.ObjectName = &relativeName;
oa.Attributes = OBJ_CASE_INSENSITIVE;
IO_STATUS_BLOCK iosb = {0};
HANDLE file = INVALID_HANDLE_VALUE;
NTSTATUS status = NtCreateFile(
&file, FILE_WRITE_DATA | SYNCHRONIZE, &oa, &iosb, NULL,
FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE,
FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT, NULL, 0);
if (!NT_SUCCESS(status))
goto done; /* 項目がすでに存在する場合、FILE_CREATE は失敗する。 */
DWORD written = 0;
ok = WriteFile(file, data, size, &written, NULL) && written == size;
CloseHandle(file);
done:
CloseHandle(dir);
return ok;
}エンジニアリング&システム堅牢化チェックリスト
- ✓2026 年 9 月の累積更新を適用する:KB5124008(Windows 11 24H2 および 25H2)、KB5122880(23H2)、KB5124012(26H1)、または KB5122871(Server 2025)。修正済みビルドは 10.0.26100.9445、10.0.26200.9445、10.0.22631.7582、10.0.28000.2954、Server 2025 では 10.0.26100.33438。[1]
- ✓SYSTEM または管理者として動作するすべてのサービスで、パスが %ProgramData%、%TEMP%、C:\Users などユーザーが書き込める場所にある CreateFileW、DeleteFileW、MoveFileExW、CopyFileW、SetFileSecurityW の呼び出しを洗い出し、それぞれレビューを必須にする。
- ✓ディレクトリは FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT で開き、FILE_ATTRIBUTE_REPARSE_POINT が付いたものは拒否し、その中で作業する間はハンドルを FILE_SHARE_DELETE なしで開いたままにする。[6], [9]
- ✓書き込む前に、開いたハンドルに対して GetFinalPathNameByHandleW で対象を確認する。自分で組み立てたパス文字列を決して信用しない。[7]
- ✓共有ディレクトリでは CREATE_ALWAYS ではなく CREATE_NEW(または NtCreateFile の FILE_CREATE)を使い、同名ファイルやリンクが既にあれば上書きせず処理を失敗させてください。[8]
- ✓サービスの作業ディレクトリは、SYSTEM と Administrators だけに書き込みを許す明示的な DACL で作成し、icacls が Users や Authenticated Users の書き込みを示したらインストーラーのテストを失敗させる。[10]
- ✓サービスが呼び出し側の代理でファイル操作を行う場合は、その呼び出し側になりすまし(RpcImpersonateClient、ImpersonateNamedPipeClient)、アクセスを SYSTEM ではなくその者のトークンで検査する。
- ✓標準ユーザーのプロセスが %ProgramData% や %windir% の下にジャンクションやマウントポイントを作成したら警告する。通常の利用ではまれで、リンク追跡攻撃はこうして始まる。
- ✓検証済みディレクトリハンドルを基点に
NtCreateFileとFILE_CREATEで子ファイルを作成してください。ディレクトリ確認後に、連結したパスでstagingDir\nameを開き直してはいけません。[8]
参考資料
- マイクロソフト セキュリティ レスポンス センター — CVE-2026-81963、Windows Update スタックの権限昇格の脆弱性
- CVE-2026-81963 — CVE レコード
- NVD — CVE-2026-81963
- CISA — Known Exploited Vulnerabilities カタログ
- MITRE CWE-59:ファイルアクセス前のリンク解決の不備
- Microsoft Learn — CreateFileW
- Microsoft Learn — GetFinalPathNameByHandleW
- Microsoft Learn — NtCreateFile (directory-relative names)
- Microsoft Learn — Reparse points and file operations
- Microsoft Learn — GetSecurityInfo (owner and DACL)
- MITRE CWE-284: Improper Access Control
- MITRE CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition