TL;DR: Eine Nonce in der Seite ist kein Geheimnis, und das Plugin wusste es: Eine schlafende Einreichungsfunktion veröffentlichte ihre Request-Tokens und machte den Upload-Endpunkt durch Lesen des Quelltexts erreichbar. Ich zeige den dauerhaften Fix — Entfernen.
Ausgangslage
Ich habe das Ziel als Black-Box geprüft: keine Zugangsdaten, nur die öffentlich sichtbare Fläche. Das ist, was ich sah, bevor ich etwas angefasst habe.
Ein Business-Innovationsnetzwerk mit öffentlichem Veranstaltungskalender, Newsletter-Integration und Caching-Layer auf einer vollständig gepatchten Content-Plattform. Geprüft wurden Plugin-Konfiguration, Drittanbieter-Skript-Integrität, E-Mail-Authentifizierung, Header-Policy und Benutzer-Enumeration.
Ich habe alle identifizierenden Informationen entfernt. Das Ziel wird ausschließlich nach Branche und Technologieklasse beschrieben, damit das Muster übertragbar bleibt.
Das Muster
Das Muster, das ich erkannt habe — und das ich in ähnlichen Landschaften immer wieder finde:
Ein Request-Token ist ein gutes Design. Die nächste Frage lautet, wo er liegt. Nonces werden dem Browser bewusst übergeben, weil der Browser beweisen muss, dass er das Formular geladen hat. Das bedeutet, der Wert steht per Design im Seitenquelltext, was in Ordnung ist, solange er an eine Sitzung gebunden ist und schnell abläuft.
Ein Veranstaltungskalender mit Front-End-Einreichung nimmt Datei-Uploads an, weil der Kalender öffentlich ist. Der Einreichungs-Endpunkt braucht ein Token gegen Spam. Das Token steht in der Seite. Das Upload-Verzeichnis und die Validierungsroutine sind damit für jeden lesbar, und der Form-Handler einer ungenutzten Funktion ist weiterhin deployed.
Das allgemeine Muster ist schlafende Funktionalität. Funktionen für ein bestimmtes Ereignis oder einen Workflow überleben ihren Zweck im Plugin, weil das Entfernen einer Plugin-Einstellung niemandes Ticket ist.
Befunde
| Schweregrad | Befund | Nachweis |
|---|---|---|
| MITTEL | Einreichungsfunktion aktiv mit im Seitenquelltext veröffentlichten Tokens | Upload-Endpunkt durch Lesen des Quelltexts erreichbar |
| MITTEL | Content Security Policy siteweit nicht vorhanden | Keine Policy trotz installiertem Consent-Plugin |
| MITTEL | Fünf Drittanbieter-Skripte ohne Integritätsattribute | Keine Subresource Integrity auf externen Skripten |
| MITTEL | E-Mail-Authentifizierung nur überwacht | Absenderdomain fälschbar |
| NIEDRIG | Benutzer-Enumeration über drei getrennte Pfade | Lese-Schnittstelle, Login-Fehlertext und Author-Redirect |
| NIEDRIG | Caching-Layer exponiert internen Header mit der Softwarebezeichnung | Cache-Software und Konfigurationsflags sichtbar |
Der Angriffspfad
Reproduktion im Labor
Jeder Befehl unten zielt auf einen Lab-Container, den ich selbst kontrolliere. Nichts davon ist auf ein laufendes System gerichtet.
Veröffentlichte Request-Tokens im eigenen Seitenquelltext finden
$ curl -s https://example.org/events/ > /tmp/page.html
# nonce-ähnliche Werte im Markup
$ grep -oiE '(nonce|_wpnonce|mec[a-z_]*nonce|verification)["\x27:=\s]+[a-z0-9]{8,}' /tmp/page.html | head
# welche Formulare und Endpunkte die Seite referenziert
$ grep -oiE 'action=["\x27][^"\x27]+|admin-ajax\.php[^"\x27]*' /tmp/page.html | sort -u | head
Erkennung in eigener Infrastruktur
Externe Skripte inventarisieren und auf Integritätsattribute prüfen
$ curl -s https://example.org/ | grep -oE '<script[^>]*src="[^"]*"[^>]*>' \
| grep -v 'src="/' \
| sed 's/.*src="\([^"]*\)".*/\1/' | sort -u
# und zählen, wie viele davon Integrität tragen
$ curl -s https://example.org/ | grep -oE '<script[^>]*src="https?://[^"]*"[^>]*>' \
| grep -c integrity
Behebung
Die Funktion abschalten, wenn sie keinen Besitzer hat
# die dauerhafte Behebung für schlafende Funktionalität ist Entfernen, nicht Harten
import subprocess
# was auf dieser Installation aktiv ist
$ wp plugin list --status=active --field=name
$ wp option get mec_options --format=json | python3 -c '
import json,sys
cfg = json.load(sys.stdin)
fe = cfg.get("features", {})
for name, state in fe.items():
print(name, state)'
# den anonymen Einreichungspfad deaktivieren und erneut testen
$ wp option patch update mec_options '{"features":{"fes_nonce":false,"fes_upload_nonce":false,"recaptcha_key":""}}'
Externe Skripte mit Integritätsattributen pinnen
<!-- jedes Drittanbieter-Skript bekommt ein Integritätsattribut -->
<script src="https://cdn.example.com/analytics.js"
integrity="sha384-EXAMPLEHASHEXAMPLEHASHEXAMPLEHASHEXAMPLEHASHEXAMPLEHASH"
crossorigin="anonymous"></script>
Sobald ein Angreifer Zugriff hat, kann er folgende Aktionen durchführen:
Fazit — was ich daraus mitnehme
- Ein Token in der Seite ist normal; ein Token, der eine ungeprüfte Fähigkeit schützt, ist ein Befund.
- Schlafende Funktionen überleben ihren Zweck im Plugin.
- Die dauerhafte Behebung für eine ungenutzte Funktion ist Entfernen, keine Konfigurationsänderung.
- Wenn ein Consent-Plugin installiert ist, sollte der CSP-Generator aktiv sein.