
Element Web v1.12.29 - Élevé - À distance - Session - fragment guest creds wipe a real session before whoami
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · element-fragment-guest
Analyse détaillée : https://abraxaslabs.tech/research/element-fragment-guest
Element Web v1.12.29 - Element / New Vector
Classe : Destruction de session Portée : À distance
Lifecycle.loadSession privilégie guest_user_id et guest_access_token issus du fragment d'URL plutôt que restoreSessionFromStorage. Les invités sont activés par défaut (enableGuest={!config.disable_guests}). Le config.json de app.element.io ne définit pas disable_guests. onTokenLoginCompleted ne supprime que les paramètres SSO et OIDC. Il ne supprime jamais les clés invité. url_utils.ts commente déjà que ces paramètres de fragment semblent inutilisés. Ils l'emportent tout de même.
Quiconque parvient à faire ouvrir à un utilisateur connecté une URL avec fragment contenant des paramètres invité le déconnecte et efface sa cryptographie locale. Un jeton bidon suffit. whoami n'est jamais appelé.
| ID | pas encore de CVE |
| CWE | CWE-384 / CWE-352 / CWE-613 |
| CVSS | Élevé : 7.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H |
| Produit | Element Web |
| Affecté | tag v1.12.29 v1.12.29 (2d90d6b7b601ecb9ccdf81239a43b4396b4b0c9e). Invités activés (par défaut). |
| Authentification | attaquant non authentifié. La victime doit ouvrir (ou recharger) une URL. |
| Licence | GNU Affero GPL v3.0 |
| Labo | 127.0.0.1 uniquement |
Amener un utilisateur connecté à ouvrir une URL avec fragment contenant des paramètres invité. Le client le déconnecte, efface sa cryptographie locale et peut le placer sur un invité contrôlé par l'attaquant. Il s'agit d'une déconnexion et d'un effacement de la cryptographie. Ce n'est pas le vol du vrai jeton. Ce n'est pas une RCE au niveau de l'OS.
| Privilège | Méthode / point de terminaison | Reconnaissance / intégrité / disponibilité | Prouvé en labo ou déduit |
|---|---|---|---|
| Analyser les identifiants invité depuis le fragment | url_utils.ts guest: { keys: ["guest_user_id", "guest_access_token"], location: "fragment" } | Intégrité de la sélection de session | Prouvé en labo. #/home?guest_user_id=...&guest_access_token=... est devenu guest_params. La chaîne de requête seule ne l'a pas fait. |
| Privilégier l'invité sur une session non invitée stockée | Branche prioritaire invité de Lifecycle.loadSession, journal Using guest access credentials | Intégrité | Prouvé en labo. La session préchargée @victim:example.org n'a pas été restaurée. |
| Effacer localStorage, le compte IndexedDB, sessionStorage, la cryptographie | doSetLoggedIn(..., clearStorageEnabled=true) puis clearStorage() | Intégrité / disponibilité de la session locale | Prouvé en labo. crypto_empty=yes, le jeton précédent a disparu. |
| Ignorer la validation du jeton | Le chemin invité n'appelle jamais /_matrix/client/v3/account/whoami | Intégrité | Prouvé en labo. whoami_called=no. Le jeton bidon not-a-real-token a tout de même effacé les données. |
| Persister les identifiants invité de l'attaquant | persistCredentials après l'effacement | Intégrité | Prouvé en labo. after_user=@x:example.org, after_token=not-a-real-token, mx_is_guest=true. |
| Fixer la session sur un véritable invité du HS par défaut | Même persistance si le jeton invité est valide | Intégrité | Déduit. Le labo a utilisé un jeton bidon, donc aucune connexion HS réelle. |
| Répéter cela au rechargement | Les clés invité restent dans le fragment ; onTokenLoginCompleted ne les supprime pas | Intégrité | Déduit du code épinglé app.tsx. Le labo a ouvert l'URL une fois. |
Fermé sur ce point restant : voler le véritable jeton d'accès (il est supprimé, pas exfiltré). RCE / LPE du système d'exploitation (Desktop nodeIntegration: false, sandbox). SPA Element en direct (how=gadget). Chaîne de requête ?guest_user_id= (fragment uniquement). disable_guests: true conserve la session non invitée. Un loadSession corrigé qui ignore l'invité lorsqu'une session non invitée existe la conserve également.
Autres points restants du pin : vector: lettre de lecteur Windows, Univention ICS javascript: href.
J'ai épinglé Element Web v1.12.29 après la publication GitHub du 22 septembre 2026. Le loginToken SSO est uniquement en chaîne de requête et supprimé après usage. Les clés invité restent dans le fragment et l'emportent sur la restauration. Le commentaire dans url_utils.ts est révélateur : ils doutaient déjà que ces clés soient spécifiées.
Fausses pistes déjà consignées : traiter la chaîne de requête ?guest_user_id= comme le vecteur (les clés vivent dans le hash) ; qualifier cela de vol de jeton (le vrai jeton est supprimé, pas envoyé) ; s'attendre à disable_guests dans la config d'app.element.io (il n'est pas défini). Un reverse shell. Du théâtre.
Gadget des fonctions du pin. Pas un conteneur Element Web en direct. how=gadget.
python3 element-fragment-guest-Abraxas-Labs.py
ou
cd lab
./run.sh
Ciblez uniquement http://127.0.0.1:19600. Composez le projet element-fragment-guest. La pile est démontée après l'exécution.
SUCCESS element-fragment-guest how=gadget guest-wipe=yes prior-kept=no garbage-token=yes disable-guests-keeps=yes ELEMENT-FRAGMENT-GUEST-WITNESS
Ignorer les paramètres de fragment invité lorsqu'une session non invitée existe déjà. Valider le jeton invité avec /_matrix/client/v3/account/whoami avant clearStorage. Supprimer guest_user_id et guest_access_token de la même manière que les jetons SSO sont supprimés. Définir disable_guests: true par défaut pour l'app.element.io hébergé.
Lifecycle.ts (loadSession invité en priorité)url_utils.tsapp.tsx (enableGuest={!config.disable_guests})