FlawOpen

flawopen.com/Incidents/windows-update-stack-symlink-eop-september-2026

● Microsoft · CVE-2026-81963 · September 2026 · CVSS 7.8 · Haute
Recherche · FlawOpen

CVE-2026-81963 : lien défectueux Windows Update

CVE-2026-81963 est une faille exploitée de résolution de liens dans Windows Update. Versions touchées, correctif et ouverture sûre des fichiers.[1], [2]

💡 Explication en Langage Simple (ELI5)

Un gardien de nuit muni d'un passe-partout livre des colis à « la réserve au bout du couloir » en suivant les flèches peintes sur les murs, sans vérifier où il arrive. Les locataires ont le droit de déplacer ces flèches. L'un d'eux tourne la flèche de la réserve vers le bureau du directeur, et le gardien, dont la clé ouvre toutes les portes, entre et pose le colis sur le bureau du directeur. Le locataire n'aurait jamais pu ouvrir cette porte ; la clé du gardien l'a fait pour lui. La correction consiste à ce que le gardien lise le numéro de la porte qu'il a réellement ouverte et cesse de suivre des flèches que les locataires peuvent déplacer.[5], [9]

Concepts Clés et Termes

Windows Update Stack
Les composants de Windows qui recherchent, téléchargent, préparent et installent les mises à jour. Ils s'exécutent en SYSTEM, car installer des mises à jour implique d'écrire dans des zones protégées du système.[1]
SYSTEM (NT AUTHORITY\SYSTEM)
Le compte local sous lequel s'exécutent les services Windows. Il a plus de droits qu'un administrateur sur la machine locale ; presque aucune opération sur fichier ne lui est refusée.[1]
Jonction / lien symbolique (reparse point)
Objets NTFS qui font pointer un chemin vers un autre. Un utilisateur standard peut créer une jonction dans un dossier qu'il contrôle et rediriger ce nom vers un répertoire où il ne peut pas écrire.[9]
Suivi de liens (CWE-59)
Un programme ouvre, écrit, déplace ou supprime un fichier par son nom sans vérifier que ce nom se résout là où il l'attend ; un lien placé par quelqu'un d'autre détourne alors l'opération.[5], [2]
FILE_FLAG_OPEN_REPARSE_POINT
Un indicateur de CreateFileW qui ouvre le dernier composant du chemin lui-même s’il s’agit d’un point de réanalyse, au lieu de suivre ce dernier lien. À lui seul, il n’empêche pas le traitement des points de réanalyse dans les composants précédents.[6]
TOCTOU (CWE-367)
Time-of-check to time-of-use : le système de fichiers change entre une vérification et l'opération qui en dépend. Vérifier une chaîne de chemin puis l'ouvrir par son nom laisse cette fenêtre ouverte.[12]
CWE-284 (contrôle d’accès inadéquat)
Microsoft attribue les CWE-59 et CWE-284 à cette CVE. La CWE-59 désigne le défaut précis de résolution des liens. La CWE-284 est une Pillar CWE générale que MITRE déconseille explicitement pour le mappage de vulnérabilités réelles. Il faut la lire comme la classification plus large de Microsoft pour ce même problème signalé, et non comme la preuve d’un second bogue.[2], [11], [5]

Correspondances de référentiels

Chronologie de l'Incident

2026-08-27

Microsoft réserve CVE-2026-81963.[2]

2026-09-08

Patch Tuesday de septembre : Microsoft publie le correctif et marque la faille « Exploitation Detected » et non divulguée publiquement.[1]

2026-09-08

La CISA ajoute CVE-2026-81963 au catalogue Known Exploited Vulnerabilities, avec une échéance de correction au 22 septembre 2026 pour les agences fédérales américaines.[4]

2026-09-15

Microsoft publie une révision de l'avis.[1]

Déroulement de l'Attaque Étape par Étape

Étape 1

Un service SYSTEM travaille dans un chemin modifiable par les utilisateurs

Les composants de l'Update Stack s'exécutent en SYSTEM et manipulent des fichiers dans des répertoires de préparation et de travail. Si un utilisateur standard peut créer, supprimer ou renommer des entrées n'importe où sur ce chemin, c'est lui qui décide où il se résout. Microsoft n'a pas précisé quel chemin était concerné ici.[1]

Étape 2

Le chemin est redirigé

Une jonction ou un lien symbolique fait pointer le nom d'un répertoire ailleurs, par exemple vers un dossier système protégé. Créer une jonction dans un dossier que l'utilisateur contrôle ne demande aucun droit d'administrateur.[5], [9]

Étape 3

Le service suit le lien

Windows résout normalement les points de réanalyse lors de l’ouverture d’un chemin. FILE_FLAG_OPEN_REPARSE_POINT concerne le composant final ; les composants précédents peuvent encore être résolus. Si le service écrit ensuite via un chemin non validé, le contrôle d’accès utilise son jeton SYSTEM. Validez le handle du répertoire et créez le fichier enfant relativement à ce handle.[6], [8]

Étape 4

Un emplacement protégé est modifié

Le service crée, écrase, déplace ou supprime un fichier à un endroit que seuls SYSTEM ou les administrateurs devraient contrôler. La FAQ de Microsoft confirme que l'exploitation donne à l'attaquant les privilèges SYSTEM.[1], [2]

Code Source : Vulnérable vs Sécurisé

Microsoft n’a publié ni la fonction touchée ni son correctif. Cet exemple défensif n’est pas le code de Microsoft. Vérifier uniquement le propriétaire ne suffit pas : le propriétaire d’un objet ne prouve pas que sa DACL refuse l’écriture aux utilisateurs standard. Ce modèle suppose que l’installateur crée le chemin fixe de staging et tous ses répertoires parents avec une DACL explicite autorisant l’écriture uniquement à SYSTEM et Administrators. La fonction ne lit ni ne valide la DACL ; les autorisations définies par l’installateur sont un prérequis de déploiement. Il valide le handle du répertoire ouvert, puis crée un nom de fichier unique relatif à ce handle avec NtCreateFile et FILE_CREATE ; il ne rouvre jamais un chemin concaténé. Testez la DACL et le comportement du système de fichiers dans les déploiements pris en charge. Installez la mise à jour Microsoft pour corriger CVE-2026-81963.[5], [6], [7], [8], [9], [10]

Extrait source: Exemple illustratif de gestion des chemins Windows ; ce n’est pas du code Microsoft

IMPLÉMENTATION VULNÉRABLE
/* Exemple illustratif, pas le code source de Microsoft : la fonction concernée n’a pas
 * été publiée. Un service SYSTEM écrit dans un répertoire de staging modifiable par les
 * utilisateurs standard.
 */
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 résout les jonctions et liens symboliques dans chaque
     * composant du chemin ; le contrôle utilise le jeton SYSTEM. Si un utilisateur
     * remplace stagingDir par une jonction, l’écriture suit sa cible.
     */
    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;
}
PATCH SÉCURISÉ ET ROBUSTE
/* Modèle de défense illustratif, ni code source ni correctif Microsoft. Le programme
 * d’installation doit créer ce chemin et chaque répertoire parent avec une DACL
 * explicite autorisant l’écriture uniquement à SYSTEM et Administrators.
 */
#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;

    /* Verrouiller l’objet répertoire ; l’absence de FILE_SHARE_DELETE empêche son
     * renommage.
     */
    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;

    /* Ouvrir le nouvel enfant relativement à ce handle, sans jamais reconstruire le
     * chemin.
     */
    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 échoue si une entrée existe déjà. */

    DWORD written = 0;
    ok = WriteFile(file, data, size, &written, NULL) && written == size;
    CloseHandle(file);
done:
    CloseHandle(dir);
    return ok;
}

Liste de Contrôle de Sécurité pour l'Ingénierie

Sources