Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
AfterLife — Labo de détection de persistance de révocation : quand la réinitialisation du mot de passe réussit mais que l'attaquant ne part jamais. Reproduit la faille de révocation conditionnelle Strapi CVE-2026-22706, son correctif, un pack de détection à trois règles, et la règle naïve qui la manque. | Kitploit
Outils/GitHubGitHub/het-p301204/afterlife
Outils DéfensifsAnalyse des VulnérabilitésSécurité WebAuthentificationApprentissage et ÉducationRed TeamingRéponse aux IncidentsLabs et Pratique
GitHubhet-p301204/afterlife

AfterLife

Voir le dépôt
35il y a 1 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →

À propos

Labo de détection de persistance de révocation : quand la réinitialisation du mot de passe réussit mais que l'attaquant ne part jamais. Reproduit la faille de révocation conditionnelle Strapi CVE-2026-22706, son correctif, un pack de détection à trois règles, et la règle naïve qui la manque.

Partager

AFTERLIFE

Laboratoire de détection de persistance de révocation

Quand la réinitialisation du mot de passe réussit mais que l'attaquant ne part jamais.

Un laboratoire local red/blue pour une seule classe de vulnérabilité : le credential qui survit à l'événement censé le tuer. Il fournit l'exploit, la cause racine, le correctif, un pack de détection à trois règles, un audit d'état pour ce que les règles ne peuvent structurellement pas voir, une console forensique — et la règle de détection qui ne fonctionne pas, conservée dans le dépôt pour être démontrée en échec.

CI tests python rules OWASP CWE license

Démarrage rapide · La découverte · Pourquoi la détection naïve échoue · Le pack de règles · Console · Le correctif · Matrice · Tests · Docs


La même attaque contre les deux implémentations. Une barre par credential, de l'émission à la mort, regroupées en lignées. La ligne pointillée est le changement de mot de passe. En mode vulnérable, cinq barres la franchissent et continuent ; en mode corrigé, chaque barre de la lignée volée s'arrête là.

La même attaque. Les mêmes requêtes. Une seule différence. Généré par scripts/figures.py à partir du même payload que celui dessiné par la console — régénéré et comparé en CI, afin qu'une figure ne puisse pas diverger du code.


L'action de confinement qui ne confine pas```text

09:00 alice logs in ┐ refresh credential rt-001 │ the attacker steals rt-001 ┘

10:00 alice changes her password ← the one thing a victim can do alone HTTP 200 · password changed · fresh session issued

10:00:03 attacker: POST /refresh rt-002 → HTTP 200 new access credential at-004, issued 10:00:03

10:01:00 attacker: GET /me at-004 → HTTP 200 {"username": "alice", "authenticated": true}

Aucune erreur. Aucune anomalie. Aucune authentification échouée à comptabiliser. Le justificatif d'accès de l'attaquant a *trois secondes* et a été émis par le serveur, sur demande, après la réinitialisation.

Voici la vulnérabilité dans son intégralité :```python
def _revoke_for_security_change(self, user, kind, device_id):
    if device_id:
        revoke_credentials(user, device_id=device_id)   # ← the finding

Lisez cela comme le ferait un relecteur. La logique de révocation est juste là. Elle appelle la bonne fonction avec le bon périmètre. Le point de terminaison autour met à jour le hachage du mot de passe, renvoie 200, et émet une nouvelle session — chaque comportement observable d'un changement de mot de passe correct est présent.

Et si l'appelant omet device_id, rien n'est révoqué, et le point de terminaison signale toujours un succès.

Ce n'est pas hypothétique. C'est CVE-2026-22706 dans Strapi ≤ 5.33.2, où l'étape d'invalidation du refresh-token était conditionnée à un deviceId fourni par l'appelant. Noté 2.1, Faible. Discuté ci-dessous.


Pourquoi cela compte

Le score est faible parce que l'attaquant avait déjà accès — c'est la condition d'entrée, et ce bug n'accorde rien de nouveau. Ce qu'il accorde, c'est la durée, et il le fait en brisant le seul contrôle que la victime peut actionner elle-même.

  • Chaque procédure de prise de contrôle de compte commence par réinitialiser le mot de passe. Chaque produit dit la même chose à l'utilisateur.
  • Quand cela échoue silencieusement, la victime se voit dire que le problème est résolu et arrête de chercher — ce qui désactive le signal de détection qui compte le plus dans la prise de contrôle de compte : que l'utilisateur s'en aperçoive.
  • La fenêtre de persistance est la durée de vie du refresh credential : 30 jours par défaut, renouvelable indéfiniment par rotation. test_persistence_lasts_as_long_as_the_refresh_credential parcourt sept jours de temps simulé pour le montrer.
  • Il n'y a pas de seconde action que l'utilisateur peut entreprendre. Un second changement de mot de passe fait exactement autant que le premier.

Un bug noté Faible dans un chemin de confinement coûte plus qu'un bug noté Faible dans un chemin de fonctionnalité, parce que le coût est payé pendant un incident, quand personne ne lit les avis.


Le détecteur naïf

La règle que vous écrivez en premier :```text IF credential.issued_at < credential_change.timestamp: ALERT

Ce n'est pas une règle stupide. Elle est peu coûteuse, nécessite un seul champ, se lit comme la définition
du problème, et elle est **correcte pour le cas simple** — un attaquant utilisant un
jeton d'*accès* volé après la réinitialisation se fait prendre.
`test_the_naive_rule_catches_the_simple_case` affirme que cela fonctionne.

Les deux règles posent la même question sur le même identifiant. Elles lisent des
champs différents pour y répondre, et les deux champs sont en désaccord :

![Deux lignes, une par champ. credential.issued_at indique 10:00:03, trois secondes après le changement, et conclut que l'identifiant semble propre. lineage.root_issued_at indique 09:00:00, une heure avant le changement, et déclenche une alerte.](https://raw.githubusercontent.com/het-p301204/afterlife/main/docs/figures/two-fields.svg)

**Trois secondes après, ou une heure avant — le même identifiant, au même
instant.** La règle naïve interroge un champ contrôlé par l'attaquant, et un
seul `POST /refresh` le réinitialise.

Exécutez-la sur le journal des requêtes, qui est l'endroit où cette requête est réellement écrite,
car les journaux de requêtes sont ce que vous avez :```text
NAIVE DETECTOR (NAIVE-001), over the request log

  Result: NO ALERT

  Six requests were served to the attacker after the reset. Every one of them
  carried at-004, minted at 10:00:03 -- three seconds *after* the password
  change. By its own timestamp it is the newest credential on the account.

Il serait facile de s'arrêter là, et malhonnête, donc le lab exécute aussi la version la plus équitable de la règle naïve — élargie pour surveiller également le point de terminaison de rafraîchissement :```text NAIVE DETECTOR, widened to include POST /refresh

1 alert at 2026-09-11T10:00:03.000Z: the credential presented to /refresh was rt-002, issued 2026-09-11T09:30:00.000Z. Then it goes blind. 6 events follow that hop and it flags none of them, because every credential from there on carries a post-reset timestamp. Its incident covers 1 accepted request; the lineage rule's covers all of them.

Télécharger l’outil