
Python-CLI, die CVE-2026-90907 erkennt und ausnutzt, eine Autorisierungsumgehung in Joomla! com_users, die unauthentifizierte Kontoerstellung ermöglicht; nicht-destruktiver Prüfmodus plus PoC.
NUR FÜR AUTORISIERTE SICHERHEITSTESTS. Das Ausführen des Exploit-Modus gegen Systeme, die Ihnen nicht gehören oder für die Sie keine ausdrückliche schriftliche Erlaubnis zum Testen haben, ist illegal. Der Standardmodus (
CHECK) ist nicht destruktiv und erstellt nichts.
CLI-Tool, das CVE-2026-90907 erkennt und (optional, mit -U) ausnutzt — eine
Autorisierungs-Umgehung mittlerer Schwere (CVSS 6.9) im Joomla! CMS-Kern,
die es einem nicht authentifizierten Remote-Angreifer ermöglicht, die unautorisierte
Erstellung von Benutzerkonten über den com_users → profile.save-Controller auszulösen —
selbst wenn die öffentliche Registrierung in der Globalen Konfiguration deaktiviert ist.
| Feld | Wert |
|---|---|
| CVE-ID | CVE-2026-90907 |
| Schweregrad | Mittel — CVSS 6.9 |
| Typ | Autorisierungs-Umgehung / unsachgemäße Zugriffskontrolle (CWE-862) |
| Komponente | com_users-Komponente, profile.save-Task |
| Angriffsvektor | Remote, nicht authentifiziert, zweistufiger POST innerhalb derselben Sitzung |
| Behoben in | Joomla! 5.4.9 und 6.1.4 (Sicherheitsrelease, 2026-09-29) |
Gemäß dem Joomla!-Sicherheitsbulletin (2026-09-29) und öffentlichen Advisory-Quellen:
Joomla! 3.x ist ebenfalls betroffen, aber End-of-Life: Es wird keinen offiziellen Patch erhalten — planen Sie eine Migration. Die Versionsbanner-Prüfung des Tools ist informativ; das Urteil erfolgt verhaltensbasiert (siehe unten).
Das vom Angreifer kontrollierte Konto ist ein Front-End-Konto mit geringen Rechten ohne administrativen oder Backend-Zugriff. Dennoch ermöglicht dies einem Angreifer:
ProfileModel::save() führt nur dann ein unset() auf $data['username'] aus, wenn der Benutzername
als konform gilt. isUsernameCompliant wird aus dem Benutzer-
zustand com_users.edit.profile.data abgeleitet, den der Controller mit der
vollständigen Anfrage befüllt, wenn die Formularvalidierung fehlschlägt. Der Controller versäumt es außerdem,
den Anmeldestatus der eingehenden Anfrage zu überprüfen. Daher gilt innerhalb einer Gast-
sitzung:
privacyconsent → Validierung schlägt fehl → der fehlerhafte Benutzername wird im
Sitzungs-Benutzerzustand gespeichert (es wird noch nichts erstellt).jform[privacyconsent][privacy]=1 → die unset()-Sperre wird übersprungen →
INSERT INTO #__users → 303-Weiterleitung mit user_id > 0.user.login (Feldname ist
password, nicht passwd) mit dem korrekten vs. einem falschen Passwort und
Auslesen der Flash-Nachricht: korrekt → "you cannot access the private section"
(Auth OK, ACL blockiert) / falsch → "do not match". Die Differenz ist
der Beweis.git clone https://github.com/aorozco-sys/CVE-2026-90907.git
cd CVE-2026-90907
pip install -r requirements.txt # only dependency: requests
# CHECK mode (default) — non-destructive: never sends consent, never creates an account
python3 joomla_cve_2026_90907.py https://ejemplo.com
# Verbose CHECK (full request/response log on stderr)
python3 joomla_cve_2026_90907.py https://ejemplo.com --no-color -v
# EXPLOIT mode (-U) — creates a real account in #__users (authorized targets only!)
python3 joomla_cve_2026_90907.py https://ejemplo.com \
-U audit.user -E [email protected] -N "CVE Audit"
# Through a proxy (e.g. Burp Suite) with a custom timeout
python3 joomla_cve_2026_90907.py https://ejemplo.com -U audit.user \
--proxy http://127.0.0.1:8080 --timeout 30
# Exploit without the differential login verification
python3 joomla_cve_2026_90907.py https://ejemplo.com -U audit.user \
--no-verify-login
| Flag | Beschreibung |
|---|---|
TARGET | Basis-URL (normalisiert; kein abschließender Schrägstrich) |
-U/--username | Aktiviert den EXPLOIT-Modus. Ohne -U → nicht-destruktiver CHECK |
-P/--password | Standard: generiert mit secrets, 16 Zeichen alphanumerisch+Symbole, wird immer ausgegeben |
-E/--email | Standard: <username>@example.invalid |
-N/--name | Standard: CVE Audit |
-o/--output | Evidenzverzeichnis (Standard evidence_cve90907_<ts> unter cwd) |
--proxy URL | Proxy für Anfragen (Burp: http://127.0.0.1:8080) |
--timeout | Standard 20 s |
--ua | User-Agent (Standard cve-2026-90907-audit/1.0) |
--no-verify-login | Überspringt das Login-Differential (Exploit-Modus) |
--verify-ssl | TLS verifizieren (Standard: nicht verifizieren) |
--no-color | Keine ANSI-Farben |
-v/--verbose | Vollständiges Req/Resp-Log auf stderr |
| Code | Bedeutung |
|---|---|
0 | Ok / nicht anfällig / unbekannt |
1 | Anfällig (LIKELY im Check, CONFIRMED im Exploit) |
2 | Betriebsfehler (Netzwerk, Abhängigkeit usw.) |
profile in Location, keine Weiterleitung zum Login) + Validierungsfehler-
Flash (z. B. Meldung, dass die Datenschutzrichtlinie erforderlich ist). Endgültige Bestätigung =
Exploit-Modus.summary.json aufgeführt.Location mit user_id > 0 nach W2.Jeder Lauf schreibt ein zeitgestempeltes -o-Verzeichnis mit 00_token.txt,
01_version.txt, 02_w1_seed.txt, 03_w2_exploit.txt,
04_login_correct.txt, 05_login_wrong.txt und summary.json. Jede Datei
zeichnet die vollständige REQUEST (Methode/URL/Schlüssel-Header/Body), RESPONSE (Status,
Location, Server, extrahiertes Flash, erste 500 Bytes des Bodys) und ISO-
Zeitstempel auf — bereit zur Anlage an einen Pentest-Bericht.
privacyconsent und verwendet einen nicht-konformen
Benutzernamen (probe()): Das Speichern schlägt an den Formularregeln fehl und nichts wird persistiert.user_id > 0 zurückgegeben hat (was nicht der Fall sein sollte), bricht der Exploit-
Modus vor W2 ab.user_usergroup_map-Zeile).