CTF Write-Up

entièrement en français et réalisé par ThaySan.

View on GitHub

[Web] Anozer Blog - 258pts

Anozer Blog.zip

title: Anozer Blog

category: Web

difficulty: Medium

point: 258

author: JeanJeanLeHaxor#4628

description:

Objective: Read the flag, situated on the server in /app/flag.txt

Solution

Le code source est donné. En regardant le fichier requirements.txt on peut déjà voir que pydash est demandé en version 5.1.2 spécifiquement, c’est assez étrange alors regardons s’il existe des vulnérabilités dessus.

Je suis tombé sur cet article expliquant comment polluer une variable grâce à PyDash :

Article sur la pollution avec pydash

Accompagné de cet exemple :

pydash.set_(User(), '__class__.__init__.__globals__.not_accessible_variable','Polluted variable')

On peut donc changer la valeur d’une variable qui n’est pas accessible dans notre contexte grâce à la fonction set_.

Cherchons si cette fonction est utilisée :

Recherche et utilisation de la fonction set_ de pydash

Documentation de la fonction set_

Comment l’exploiter ? Il faut que article_name soit le path de notre variable à polluer et article_content soit notre value de pollution.

Pour arriver à cette fonction, il faut passer par la création d’un article :

Code de la fonction 'create_article'

Ok, à priori on peut modifier n’importe quelle variable, mais sur laquelle le faire ?

L’objectif est de lire un fichier local, or on ne peut pas exécuter de commande via la pollution directement puisque dans notre fonction create_article on nous impose ligne 21 que content soit une string.

En cherchant un peu plus, on tombe sur cette fonction qui permet d’utiliser render_template_string si le user a la propriété seeTemplate vraie. Cette fonction permettrai de faire une SSTI dans Jinja et donc d’exécuter directement des commandes.

Code de la fonction 'render_page'

Et dans le fichier users.py, on voit qu’un compte admin est automatiquement ajouté avec cette permission.

Création du compte admin dans l'initialisation de la class Users

Et bien je propose de modifier le secret de la création des tokens d’authentification pour forger nos tokens et se connecter en tant qu’admin pour exécuter notre payload.


Etape 1 : Modifier le secret

En essayant le payload que nous avons trouvé sur le site tout à l’heure ça n’a pas fonctionné, mais j’ai trouvé ce WriteUp qui propose un autre path pour accèder aux variables globales :

pydash.set_(
    TaskManager(),
    '__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.xxx',
    'xxx'
)

On va donc essayer :

path:  __init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.secret_key
value: myNewSecretKey

Envoie du payload pour polluer app.secret_key

Maintenant pour vérifier que la clé a bien été modifiée, on va créer un compte pour obtenir un token :

Création d'un compte

Puis dans le devtools > Application > Cookie on récupère le token :

Récupération du token d'authentification

Avec flask-unsign on décode le token :

> flask-unsign --decode --cookie "eyJ1c2VyIjp7InNlZVRlbXBsYXRlIjpmYWxzZSwidXNlcm5hbWUiOiJUaGF5U2FuIn19.ZF3p_g.WO5brOHD0p_cydPSxNVnA69780k"
{'user': {'seeTemplate': False, 'username': 'ThaySan'}}

Puis on en forge un nouveau avec le username admin et notre nouveau secret :

> flask-unsign --sign --cookie "{'user': {'seeTemplate': False, 'username': 'admin'}}" --secret "myNewSecretKey"
eyJ1c2VyIjp7InNlZVRlbXBsYXRlIjpmYWxzZSwidXNlcm5hbWUiOiJhZG1pbiJ9fQ.ZF3wdA.Kp-qp6YiWF1cLe5RIe9MT1-Sll0

On remplace notre ancien token par celui que l’on vient de forger et en allant consulter l’article welcome, on voit bien que l’on est connecté en tant qu’admin et que le template est interprété :

Vérification de notre token forgé


Etape 2 : lire le fichier /app/flag.txt

Pour ça j’utilise ce CheatSheet sur les SSTI de Jinja2. On y trouve le payload :

{{ request.__class__._load_form_data.__globals__.__builtins__.open("/app/flag.txt").read() }}

Il ne reste plus qu’à créé un article avec ce content :

Envoie de notre payload pour SSTI

Et maintenant on consulte l’article :

Récupération du flag

FLAG : PWNME{de3P_pOL1uTi0n_cAn_B3_D3s7rUctIv3}