Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
Tools/GitHubGitHub/griisemine/cve-2026-87902-detection
Defensive ToolsIndicator of Compromise (IOC) ManagementVulnerability ScannersVulnerability AnalysisWeb SecurityPenetration TestingIncident ResponseLog AnalysisLabs & Practice

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
GitHubgriisemine/cve-2026-87902-detection

cve-2026-87902-detection

Detection toolkit and reproducible lab for CVE-2026-87902, an unauthenticated WordPress path traversal. Includes remote checker, IoC analyzer, Sigma rules, and Docker test bench.

View Repository
1221h 20m agoNot yet reviewed
Share

wp-ghsa-7hp8-lab

Outillage de détection et banc d'essai reproductible pour GHSA-7hp8-65ch-5whp / CVE-2026-87902 — unauthenticated path traversal in page-template resolution leading to conditional RCE (WordPress, CWE-98, CVSS 4.0 : 9.2).

check/Contrôleur distant, passif, sans accès au serveur
detect/Analyseur d'IoC + règles Sigma
offensive/Générateur de traces, pour valider la détection sur des journaux réels
docker-compose.yml + provision/Banc d'essai, trois configurations
tests/validate.pyPorte de qualité — conditionne toute publication
docs/ANALYSIS.mdLa vulnérabilité, le correctif, l'analyse d'atteignabilité mesurée
root@kitploit:~
make up      # monte le banc      make ioc    # corpus d'attaque -> journaux -> détection
make scan    # contrôle le banc   make test   # porte de qualité

1. Le banc d'essai

Trois instances WordPress sur 127.0.0.1, qui isolent chaque facteur du verdict.

PortInstanceCœurThème actifVerdict attendu
8091vuln-pre6.8.1 — non corrigéTwenty Twelve, avec page-templates/AFFECTED_PRECONDITION_MET
8092vuln-nopre6.8.1 — non corrigéTwenty Twenty-Four, sans page-*AFFECTED_CORE_ONLY
8093patched6.8.10 — corrigéTwenty Twelve, avec page-templates/NOT_AFFECTED

8092 est la plus instructive : même cœur vulnérable que 8091, mais le prérequis thème manque. C'est ce qui montre qu'un triage fondé sur la seule version surestime l'exposition. Le thème est la seule variable entre 8091 et 8092, le correctif la seule entre 8091 et 8093 : les trois embarquent le même type de contenu personnalisé (provision/mu-plugins/00-lab-cpt.php) et la même sonde d'état de requête (10-lab-debug.php, en-têtes X-Lab-* qui exposent is_page(), la valeur de pagename vue par le chargeur et le template finalement inclus).

root@kitploit:~
make up        # démarre et provisionne — idempotent, relançable
make status    # version de chaque instance
make down      # arrêt        make clean : supprime aussi les volumes

Où récupérer les journaux

L'image Docker officielle fait pointer /var/log/apache2/access.log vers /dev/stdout : les journaux sortent sur la sortie du conteneur, pas dans un fichier.

root@kitploit:~
docker compose logs --no-log-prefix vuln-pre                  # accès + erreurs
docker compose logs --no-log-prefix vuln-pre > access.log     # pour analyse
docker compose logs -f --no-log-prefix vuln-pre               # en direct
make logs                                                     # les trois instances

Sur un serveur classique : /var/log/apache2/access.log, /var/log/nginx/access.log, ou /home/*/logs/ chez la plupart des hébergeurs mutualisés. Le format doit inclure la chaîne de requête — %r ou le format combined l'incluent, un LogFormat bâti sur %U la perd, et sans elle aucune détection n'est possible.

2. Le contrôleur — check/wp-ghsa-7hp8-check.py

Depuis Internet, sans accès au serveur. Aucune charge, aucun traversal, aucune écriture. Pour chaque hôte : détection WordPress, version recoupée sur cinq sources (meta generator, flux RSS, wp-links-opml.php, readme.html, ?ver= des ressources du cœur), thème actif, et sondage du répertoire page-*.

root@kitploit:~
python3 check/wp-ghsa-7hp8-check.py --hosts-file hosts.txt --csv out.csv --json out.json
VerdictSignification
AFFECTED_PRECONDITION_METCœur vulnérable et répertoire page-* sur le thème actif. Prioritaire.
AFFECTED_THEME_UNKNOWNCœur vulnérable, thème non déterminé.
AFFECTED_CORE_ONLYCœur vulnérable, prérequis thème absent. À corriger quand même.
VERSION_UNKNOWNWordPress détecté, version masquée.
NOT_AFFECTEDVersion ≥ correctif de sa branche.

« AFFECTÉ » signifie que le code vulnérable est présent, pas qu'un attaquant peut exécuter du code. Voir docs/ANALYSIS.md.

--transport browser (défaut) pilote le Google Chrome installé ; les sous-requêtes partent d'un fetch() exécuté dans la page et héritent de sa pile TLS, de son ordre d'en-têtes HTTP/2 et de ses cookies, ce qui évite d'être filtré par un CDN avant que l'URL soit lue. --transport direct n'utilise que la bibliothèque standard. --scheme http|https évite le repli https → http, qui laisse sinon une ligne 400 avec un ClientHello TLS brut dans le journal de la cible.

Chaque requête est horodatée à la milliseconde dans un journal JSONL : identifiant de session, numéro de requête, phase, URL, statut, taille, durée, IP de sortie, marqueur. Le marqueur SECAUDIT/<nonce> part en en-tête X-Security-Audit et en suffixe d'User-Agent — ajouté, jamais substitué, pour rester visible dans un access log standard sans casser la signature de navigateur. Personnalisable via --marker.

Pas d'oracle distant. L'option --probe-inclusion effectue une comparaison différentielle sur cible inerte (wp-includes/version.php, déjà chargé au bootstrap : require_once en ferait un no-op intégral). Sur une installation standard elle renvoie NOT_REACHABLE y compris sur un cœur vulnérable, avec des réponses identiques à l'octet près entre instance corrigée et non corrigée. Ce n'est pas une limite de l'outil : WordPress répond 404 avant de consulter la hiérarchie de templates. Démonstration chiffrée dans docs/ANALYSIS.md, section 3.

3. Détection et IoC

La règle structurelle

Une regex littérale du type pagename=.*%2e%2e%2f se contourne en changeant la casse (%2E), en encodant une fois de plus (%252e), ou en panachant littéral et encodé (templates/..%2f../). Toute liste de motifs est incomplète par construction.

On part donc du code, pas de l'écriture de l'attaquant :

  1. pagename subit au plus deux décodages avant d'atteindre le disque — celui de PHP sur la chaîne de requête, puis l'urldecode() explicite de get_page_template().
  2. Pour sortir du répertoire du thème, le chemin remis à file_exists() doit contenir un composant ... Sous Linux, le répertoire parent s'écrit exactement sur les deux octets 0x2E 0x2E ; il n'existe aucune autre représentation au niveau du système de fichiers.

Donc : décoder jusqu'à point fixe et tester à chaque niveau. C'est un sur-ensemble strict de ce que fait WordPress — ajouter une couche d'encodage ne fait que déplacer la correspondance d'un niveau, que l'on traverse aussi.

root@kitploit:~
python3 detect/wp-ghsa-7hp8-ioc.py access.log
docker compose logs --no-log-prefix vuln-pre | python3 detect/wp-ghsa-7hp8-ioc.py -
RègleSévéritéDéclencheur
GHSA-7hp8-traversal-pagenameCRITICALcomposant .. dans pagename, à n'importe quel niveau de décodage
GHSA-7hp8-traversal-paramHIGHmême primitive dans un autre paramètre (thèmes et extensions appellent aussi locate_template())
GHSA-7hp8-traversal-pathHIGHcomposant .. dans le chemin d'URL (nginx laisse passer %2f, pas Apache par défaut)
GHSA-7hp8-overlong-encodingMEDIUMsur-encodage UTF-8 (%c0%ae). Inopérant sous Linux, mais jamais légitime
GHSA-7hp8-theme-page-dir-probeLOWsondage d'un répertoire page-* de thème — la reconnaissance

Règles Sigma dans detect/sigma-wp-ghsa-7hp8.yml. Sigma ne sachant pas décoder récursivement, elles énumèrent les niveaux 0 à 3 : c'est une approximation assumée, pour le tri de premier niveau. Repasser les correspondances dans l'analyseur pour décider.

Limites — à connaître avant de s'y fier

  • POST. WP::parse_request() lit $_POST avant $_GET. pagename peut donc arriver dans un corps de requête, absent de tout access log. Couverture nécessaire au niveau WAF ou ModSecurity, sur le corps.
  • Format de journal. Sans chaîne de requête enregistrée, rien n'est détectable.
  • Tentative, pas succès. Un 404 n'atteste pas d'un échec sur toutes les configurations.

Aucune règle sur access log ne couvre le premier point. C'est une limite du support, pas de la règle — mais elle doit être connue avant d'annoncer une couverture complète.

Valider sa propre détection

offensive/generate-traces.py rejoue 12 écritures différentes de la même charge (littérale, simple/double/triple encodage, casse haute et basse, panachages, sur-encodage UTF-8, point-espace) plus 7 requêtes légitimes qui leur ressemblent (slug à points, wp-includes dans un slug, permalien à date, pourcent encodé).

Il n'obtient rien : il n'existe pas d'exploit distant pour ce vecteur sur une installation standard. Il produit des traces — c'est tout son objet.

root@kitploit:~
make ioc     # génère le corpus, récupère les journaux réels, passe l'analyseur

Attendu, et vérifié par make test sur des journaux Apache réels : 12 charges détectées sur 12 (11 CRITICAL, le sur-encodage en MEDIUM parce qu'il n'est pas exploitable sous Linux), 0 alerte sur les 7 requêtes légitimes, et détection effective à trois niveaux de décodage différents.

Cible limitée au banc local ; toute autre exige --i-have-authorization.

4. Remédiation

  1. Mettre à jour vers la version corrigée de sa branche — 7.1.2, 7.0.6, 6.9.9, 6.8.10, 6.7.9, … jusqu'à 4.7.37. Matrice complète dans le contrôleur.
  2. register_argc_argv = Off dans le php.ini du SAPI web ; désinstaller PEAR si inutilisé — c'est le pivot inclusion → exécution cité par l'avis.
  3. open_basedir limité à la racine du site : confine toute inclusion locale.
  4. Déployer les règles ci-dessus, en couvrant aussi le corps des requêtes POST.

5. Fiabilité

make test est la condition de publication : matrice des 25 branches de l'avis (pièges de comparaison inclus — 6.8.9 < 6.8.10 numériquement, pré-versions, branches hors matrice), contrôleur contre les trois instances, et règle IoC validée sur journaux réels. L'assertion NOT_REACHABLE de la sonde y est figée volontairement : si elle casse, c'est le comportement qui a changé et l'analyse doit être reprise.

Cadre d'usage

À n'utiliser que sur des actifs dont vous avez la responsabilité, ou sous mandat écrit. Le banc n'écoute que sur 127.0.0.1 ; les instances vulnérables ne doivent jamais être exposées. La sonde 10-lab-debug.php divulgue des chemins serveur : elle est réservée au banc.

Download Tool