FlawOpen

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

● Microsoft · CVE-2026-81963 · September 2026 · CVSS 7.8 · Hoch
Sicherheitsforschung · FlawOpen

CVE-2026-81963: Windows Update-Linkfehler

CVE-2026-81963 ist eine ausgenutzte Link-Auflösungs-Lücke in Windows Update. Betroffene Versionen, Microsofts Fix und sichere Dateiöffnung.[1], [2]

💡 Einfache Erklärung (ELI5)

Ein Nachtportier mit Generalschlüssel bringt Pakete in „den Lagerraum am Ende des Flurs“ und folgt dabei den Pfeilen an den Wänden, ohne zu prüfen, wo er ankommt. Die Mieter dürfen diese Pfeile umhängen. Einer dreht den Pfeil zum Lagerraum so, dass er auf das Büro der Geschäftsführung zeigt, und der Portier, dessen Schlüssel jede Tür öffnet, geht hinein und legt das Paket auf den Schreibtisch der Chefin. Der Mieter hätte diese Tür nie öffnen können; der Schlüssel des Portiers hat es für ihn getan. Die Lösung: Der Portier liest die Nummer der Tür, die er tatsächlich geöffnet hat, und folgt keinen Pfeilen mehr, die Mieter verschieben können.[5], [9]

Kernkonzepte & Begriffe

Windows Update Stack
Die Windows-Komponenten, die Updates suchen, herunterladen, bereitstellen und installieren. Sie laufen als SYSTEM, weil das Installieren von Updates Schreibzugriffe auf geschützte Teile des Betriebssystems erfordert.[1]
SYSTEM (NT AUTHORITY\SYSTEM)
Das lokale Konto, unter dem Windows-Dienste laufen. Es hat auf dem lokalen Rechner mehr Rechte als ein Administrator, daher wird ihm kaum eine Dateioperation verweigert.[1]
Junction / symbolischer Link (Reparse Point)
NTFS-Objekte, die einen Pfad auf einen anderen umleiten. Ein Standardbenutzer kann in einem Ordner, den er kontrolliert, eine Junction anlegen und diesen Namen auf ein Verzeichnis umleiten, in das er nicht schreiben darf.[9]
Link Following (CWE-59)
Ein Programm öffnet, schreibt, verschiebt oder löscht eine Datei über ihren Namen, ohne zu prüfen, ob der Name dorthin aufgelöst wird, wo es erwartet; ein von Dritten angelegter Link lenkt die Operation um.[5], [2]
FILE_FLAG_OPEN_REPARSE_POINT
Ein CreateFileW-Flag, das die letzte Pfadkomponente selbst öffnet, wenn sie ein Reparse Point ist, statt diesem letzten Link zu folgen. Es verhindert für sich genommen nicht die Auflösung von Reparse Points in vorherigen Pfadkomponenten.[6]
TOCTOU (CWE-367)
Time-of-check to time-of-use: Das Dateisystem ändert sich zwischen einer Prüfung und der Operation, die sich darauf verlässt. Einen Pfad-String zu prüfen und ihn danach über den Namen zu öffnen, lässt genau dieses Zeitfenster offen.[12]
CWE-284 (Unzureichende Zugriffskontrolle)
Microsoft ordnet dieser CVE sowohl CWE-59 als auch CWE-284 zu. CWE-59 bezeichnet den konkreten Fehler bei der Linkauflösung. CWE-284 ist eine allgemeine Pillar-CWE, deren Verwendung zur Zuordnung realer Schwachstellen MITRE ausdrücklich nicht empfiehlt. Sie ist als breitere Microsoft-Klassifizierung desselben gemeldeten Problems zu verstehen, nicht als Beleg für einen zweiten Fehler.[2], [11], [5]

Framework-Zuordnungen

Vorfall-Zeitstrahl

2026-08-27

Microsoft reserviert CVE-2026-81963.[2]

2026-09-08

September-Patchday: Microsoft veröffentlicht den Fix und kennzeichnet die Lücke als „Exploitation Detected“ und nicht öffentlich bekannt.[1]

2026-09-08

Die CISA nimmt CVE-2026-81963 in den Katalog Known Exploited Vulnerabilities auf; US-Bundesbehörden müssen bis zum 22. September 2026 patchen.[4]

2026-09-15

Microsoft veröffentlicht eine überarbeitete Fassung des Advisorys.[1]

Schritt-für-Schritt Angriffsablauf

Schritt 1

Ein SYSTEM-Dienst arbeitet in einem Pfad, den Benutzer ändern können

Komponenten des Update Stack laufen als SYSTEM und verarbeiten Dateien in Staging- und Arbeitsverzeichnissen. Kann ein Standardbenutzer irgendwo auf diesem Pfad Einträge anlegen, löschen oder umbenennen, bestimmt er, wohin der Pfad aufgelöst wird. Welcher Pfad hier betroffen war, hat Microsoft nicht mitgeteilt.[1]

Schritt 2

Der Pfad wird umgeleitet

Eine Junction oder ein symbolischer Link lässt einen Verzeichnisnamen auf einen anderen Ort zeigen, etwa einen geschützten Systemordner. Für eine Junction in einem eigenen Ordner braucht ein Benutzer keine Administratorrechte.[5], [9]

Schritt 3

Der Dienst folgt dem Link

Windows löst Reparse Points beim Öffnen eines Pfads normalerweise auf. FILE_FLAG_OPEN_REPARSE_POINT betrifft die letzte Komponente; vorherige Komponenten können weiterhin aufgelöst werden. Schreibt der Dienst anschließend über einen ungeprüften Pfad, verwendet die Zugriffskontrolle sein SYSTEM-Token. Prüfen Sie den Verzeichnis-Handle und erstellen Sie die Datei relativ zu diesem Handle.[6], [8]

Schritt 4

Ein geschützter Ort wird verändert

Der Dienst legt eine Datei an, überschreibt, verschiebt oder löscht sie an einer Stelle, die nur SYSTEM oder Administratoren kontrollieren sollten. Laut Microsofts FAQ erhält der Angreifer dadurch SYSTEM-Rechte.[1], [2]

Quellcode: Verwundbar vs. Sicher

Microsoft hat weder die betroffene Funktion noch den Patch veröffentlicht. Dieses defensive Beispiel ist kein Microsoft-Code. Die Prüfung des Besitzers allein reicht nicht aus: Aus dem Besitzer eines Objekts folgt nicht, dass seine DACL Schreibzugriffe normaler Benutzer verweigert. Das Muster setzt voraus, dass das Installationsprogramm den festen Staging-Pfad und alle übergeordneten Verzeichnisse mit einer expliziten DACL anlegt, die Schreibzugriff nur SYSTEM und Administrators erlaubt. Die Funktion liest oder prüft die DACL nicht; die vom Installationsprogramm eingerichteten Berechtigungen sind eine Bereitstellungsvoraussetzung. Es prüft den geöffneten Verzeichnis-Handle und erstellt einen einzelnen Dateinamen relativ zu diesem Handle mit NtCreateFile und FILE_CREATE; ein zusammengesetzter Pfad wird nicht erneut geöffnet. Prüfen Sie DACL und Dateisystemverhalten in den unterstützten Umgebungen. Installieren Sie Microsofts Update, um CVE-2026-81963 zu beheben.[5], [6], [7], [8], [9], [10]

Quelltextauszug: Beispiel für Windows-Pfadbehandlung; kein Microsoft-Quellcode

VERWUNDBARE IMPLEMENTIERUNG
/* Veranschaulichendes Beispiel, nicht Microsoft-Quellcode: Die betroffene Funktion
 * wurde nicht veröffentlicht. Ein SYSTEM-Dienst schreibt in ein Staging-Verzeichnis,
 * das Standardbenutzer ändern können.
 */
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 löst Junctions und symbolische Links in jeder Pfadkomponente
     * auf; die Zugriffsprüfung verwendet das SYSTEM-Token. Ersetzt ein Benutzer
     * stagingDir durch eine Junction, landet der Schreibzugriff an deren Ziel.
     */
    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;
}
GEHÄRTETER SICHERHEITS-PATCH
/* Veranschaulichendes Abwehrmuster, weder Microsoft-Quellcode noch Patch. Das
 * Installationsprogramm muss diesen Pfad und alle übergeordneten Verzeichnisse mit
 * einer expliziten DACL anlegen, die Schreibzugriff nur SYSTEM und Administrators
 * erlaubt.
 */
#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;

    /* Das Verzeichnisobjekt fixieren; ohne FILE_SHARE_DELETE kann es nicht umbenannt
     * werden.
     */
    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;

    /* Das neue Element relativ zu diesem Handle öffnen, den Pfad niemals neu
     * zusammensetzen.
     */
    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 schlägt fehl, wenn der Eintrag bereits vorhanden ist. */

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

Checkliste für Engineering & Systemsicherheit

Quellen