FlawOpen

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

● Microsoft · CVE-2026-81963 · September 2026 · CVSS 7.8 · उच्च
सुरक्षा अनुसंधान · FlawOpen

CVE-2026-81963: Windows Update लिंक दोष

CVE-2026-81963 Windows Update की link resolution में सक्रिय रूप से इस्तेमाल हुई खामी है। प्रभावित versions, patch और सुरक्षित file handling जानें।[1], [2]

💡 आसान भाषा में (ELI5)

मास्टर चाबी वाला एक रात का चौकीदार दीवारों पर बने तीरों के सहारे «गलियारे के आख़िर वाले भंडार-कक्ष» तक पार्सल पहुँचाता है और यह नहीं देखता कि वह किस कमरे में पहुँचा। किरायेदार इन तीरों को घुमा सकते हैं। एक किरायेदार भंडार-कक्ष का तीर मैनेजर के कमरे की ओर मोड़ देता है, और चौकीदार, जिसकी चाबी हर दरवाज़ा खोलती है, अंदर जाकर पार्सल मैनेजर की मेज़ पर रख देता है। वह दरवाज़ा किरायेदार ख़ुद कभी नहीं खोल पाता; चौकीदार की चाबी ने उसके लिए खोल दिया। समाधान यह है कि चौकीदार उस दरवाज़े का नंबर पढ़े जो उसने सचमुच खोला, और उन तीरों का पीछा करना बंद करे जिन्हें किरायेदार घुमा सकते हैं।[5], [9]

इस पेज के मुख्य शब्द

Windows Update Stack
Windows के वे घटक जो अपडेट खोजते, डाउनलोड करते, तैयार (स्टेज) करते और इंस्टॉल करते हैं। ये SYSTEM के रूप में चलते हैं क्योंकि अपडेट लगाने के लिए ऑपरेटिंग सिस्टम के संरक्षित हिस्सों में लिखना पड़ता है।[1]
SYSTEM (NT AUTHORITY\SYSTEM)
वह स्थानीय खाता जिसके रूप में Windows सेवाएँ चलती हैं। स्थानीय मशीन पर इसके अधिकार एक व्यवस्थापक से भी अधिक हैं, इसलिए इसकी की गई फ़ाइल क्रिया लगभग कभी अस्वीकार नहीं होती।[1]
जंक्शन / सिंबॉलिक लिंक (reparse point)
NTFS की वस्तुएँ जो एक पथ को किसी दूसरे स्थान पर हल कर देती हैं। सामान्य उपयोगकर्ता अपनी नियंत्रित फ़ोल्डर में जंक्शन बनाकर उस नाम को ऐसी डायरेक्टरी की ओर मोड़ सकता है जहाँ वह लिख नहीं सकता।[9]
लिंक-फ़ॉलोइंग (CWE-59)
कोई प्रोग्राम फ़ाइल को नाम से खोलता, लिखता, हटाता या स्थानांतरित करता है, पर यह नहीं जाँचता कि वह नाम अपेक्षित जगह पर ही हल होता है; तब किसी और का रखा लिंक क्रिया को दूसरी जगह मोड़ देता है।[5], [2]
FILE_FLAG_OPEN_REPARSE_POINT
CreateFileW का ऐसा flag जो path के अंतिम component के reparse point होने पर उसी point को खोलता है, अंतिम link को follow नहीं करता। यह flag अकेले पहले के path components में reparse-point processing नहीं रोकता।[6]
TOCTOU (CWE-367)
जाँच के समय और उपयोग के समय के बीच का अंतर: जाँच और उस पर निर्भर क्रिया के बीच फ़ाइल सिस्टम बदल जाता है। पथ की स्ट्रिंग जाँचना और फिर उसे नाम से खोलना यही झरोखा छोड़ देता है।[12]
CWE-284 (अनुचित एक्सेस कंट्रोल)
Microsoft ने इस CVE को CWE-59 और CWE-284, दोनों दिए हैं। CWE-59 लिंक-रिज़ॉल्यूशन की विशिष्ट कमजोरी बताता है। CWE-284 एक व्यापक Pillar CWE है, जिसे MITRE वास्तविक दुनिया की कमजोरियों से मैप करने के लिए स्पष्ट रूप से हतोत्साहित करता है। इसे इसी रिपोर्ट की गई समस्या के लिए Microsoft का व्यापक वर्गीकरण समझें, दूसरे बग का प्रमाण नहीं।[2], [11], [5]

फ्रेमवर्क मैपिंग

घटना का समयक्रम (Timeline)

2026-08-27

Microsoft CVE-2026-81963 आरक्षित करता है।[2]

2026-09-08

सितंबर का Patch Tuesday: Microsoft सुधार प्रकाशित करता है और ख़ामी को «Exploitation Detected» तथा सार्वजनिक रूप से अघोषित के रूप में चिह्नित करता है।[1]

2026-09-08

CISA इसे Known Exploited Vulnerabilities सूची में जोड़ता है; अमेरिकी संघीय एजेंसियों के लिए सुधार की समय-सीमा 22 सितंबर 2026 है।[4]

2026-09-15

Microsoft सलाह का संशोधित संस्करण प्रकाशित करता है।[1]

हमले का चरण-दर-चरण प्रवाह

चरण 1

SYSTEM सेवा ऐसे पथ में काम करती है जिसे उपयोगकर्ता बदल सकते हैं

Update Stack के घटक SYSTEM के रूप में चलते हैं और स्टेजिंग तथा कार्यशील डायरेक्टरियों में फ़ाइलें संभालते हैं। अगर सामान्य उपयोगकर्ता उस पथ पर कहीं भी प्रविष्टियाँ बना, हटा या नाम बदल सकता है, तो पथ कहाँ हल होगा यह वही तय करता है। इस मामले में कौन-सा पथ प्रभावित था, Microsoft ने नहीं बताया।[1]

चरण 2

पथ को मोड़ दिया जाता है

जंक्शन या सिंबॉलिक लिंक किसी डायरेक्टरी के नाम को कहीं और, जैसे किसी संरक्षित सिस्टम फ़ोल्डर, पर हल करा देता है। अपनी नियंत्रित फ़ोल्डर में जंक्शन बनाने के लिए व्यवस्थापक अधिकार नहीं चाहिए।[5], [9]

चरण 3

सेवा लिंक का पीछा करती है

Windows path खोलते समय सामान्यतः reparse points resolve करता है। FILE_FLAG_OPEN_REPARSE_POINT अंतिम component पर लागू होता है; पहले के components फिर भी resolve हो सकते हैं। यदि सेवा बाद में unvalidated path से लिखती है, तो access check सेवा के SYSTEM token से होता है। Directory handle सत्यापित करें और child file उसी handle के सापेक्ष बनाएँ।[6], [8]

चरण 4

संरक्षित स्थान बदल दिया जाता है

सेवा ऐसी जगह फ़ाइल बनाती, अधिलेखित करती, स्थानांतरित करती या हटाती है जिसे केवल SYSTEM या व्यवस्थापकों को नियंत्रित करना चाहिए। Microsoft का FAQ पुष्टि करता है कि इसके दुरुपयोग से हमलावर को SYSTEM विशेषाधिकार मिल जाते हैं।[1], [2]

सोर्स कोड: कमज़ोर बनाम सुरक्षित कार्यान्वयन

Microsoft ने प्रभावित फ़ंक्शन या पैच प्रकाशित नहीं किया है। यह सुरक्षा उदाहरण Microsoft का कोड नहीं है। केवल owner की जाँच पर्याप्त नहीं है: किसी ऑब्जेक्ट का मालिक होना यह साबित नहीं करता कि उसकी DACL सामान्य उपयोगकर्ताओं को लिखने से रोकती है। यह पैटर्न मानता है कि इंस्टॉलर तय staging path और उसके सभी parent directories को स्पष्ट DACL के साथ बनाता है, जिसमें केवल SYSTEM और Administrators को लिखने की अनुमति हो। यह फ़ंक्शन DACL को पढ़ता या सत्यापित नहीं करता; इंस्टॉलर द्वारा पहले से तय अनुमतियाँ deployment की पूर्वशर्त हैं। यह खुले directory handle की जाँच करता है और NtCreateFile तथा FILE_CREATE से उसी handle के सापेक्ष एक child filename बनाता है; जोड़ा हुआ path दोबारा नहीं खोलता। समर्थित deployments में DACL और filesystem व्यवहार जाँचें। CVE-2026-81963 को ठीक करने के लिए Microsoft update इंस्टॉल करें।[5], [6], [7], [8], [9], [10]

सोर्स अंश: Windows path handling का उदाहरण; Microsoft का source code नहीं

कमज़ोर कार्यान्वयन
/* यह illustrative उदाहरण है, Microsoft का source code नहीं: प्रभावित function प्रकाशित
 * नहीं किया गया है। SYSTEM के रूप में चलने वाली service ऐसी staging directory में file
 * लिखती है जिसे सामान्य users बदल सकते हैं।
 */
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 path के हर component में junction और symbolic link resolve
     * करता है; access check SYSTEM token से होता है। यदि user stagingDir को junction से
     * बदल दे, तो write उसके target पर पहुँचता है।
     */
    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;
}
सुरक्षित और सुदृढ़ फ़िक्स
/* यह illustrative defensive pattern है, Microsoft का source या patch नहीं। Installer को
 * इस path और सभी parent directories को explicit DACL के साथ बनाना चाहिए, जो केवल SYSTEM
 * और Administrators को write की अनुमति दे।
 */
#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;

    /* Directory object को pin करें; FILE_SHARE_DELETE हटाने से rename रुकता है। */
    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;

    /* Path फिर से बनाए बिना इसी handle के relative नया child खोलें। */
    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; /* Entry पहले से मौजूद हो तो FILE_CREATE विफल होता है। */

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

इंजीनियरिंग और सिस्टम सुरक्षा चेकलिस्ट

स्रोत