Introduction

Writeup d’un challenge que j’ai proposé pour le Midnightflag ctf. L’objectif est d’obtenir le flag situé dans le fichier /root/flag.txt du serveur. Pour ce faire les joueurs devront exploiter une webapp flask.

form

On lance une énumération classique des dossiers sur le serveur web.

gobuster dir -u http://172.17.0.2:8181/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt               
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://172.17.0.2:8181/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/04/28 14:35:02 Starting gobuster in directory enumeration mode
===============================================================
/login                (Status: 200) [Size: 711]
/signup               (Status: 200) [Size: 764]
/logout               (Status: 302) [Size: 248] [--> http://172.17.0.2:8181/login?next=%2Flogout]
/scan                 (Status: 200) [Size: 40]

On remarque aussi que /scan existe, elle est pour le moment inaccessible. Une page d’inscription est disponible, on peut alors essayer de s’inscrire.

form

Une fois authentifié sur le site on essaye de se rendre sur la page de scan, toujours inaccessible. On remarque alors que notre cookie de session est un cookie flask.

form

On peut alors essayer de decoder le cookie avec flask-unsign.

form

Essayons maintenant de bruteforcer la clé permettant de signer le cookie.

form

Bingo ! on obtient la secret key : coldwar.

On peut maintenant modifier le champ user_id de notre cookie pour lui attribuer la valeur 1.

form

Nous pouvons maintenant utiliser le cookie pour obtenir une session admin et accéder à la page /scan.

form

Step 2 : Exploitation d’une Server Side Template Injection

Sur la page de scan nous trouvons une input demandant une url. On lance notre serveur web et on rentre notre url.

form

Le web serveur fait plusieurs requêtes sur notre serveur.

spawnzii@spz:/var/www/html$ python3 -m http.server 9090
Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ...
127.0.0.1 - - [28/Apr/2022 15:15:35] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [28/Apr/2022 15:15:35] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [28/Apr/2022 15:15:35] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [28/Apr/2022 15:15:35] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [28/Apr/2022 15:15:35] code 404, message File not found
127.0.0.1 - - [28/Apr/2022 15:15:35] "GET /robots.txt HTTP/1.1" 404 -
127.0.0.1 - - [28/Apr/2022 15:15:35] "GET / HTTP/1.1" 200 -

Nous avons certaines informations en retour, comme le titre, le robots.txt,les fichiers js …

form

On peut essayer de modifier le titre de notre serveur web en plaçant par exemple {{7*7}}. form

Le titre est filtré, nous obtenons {7*7}.

form

Il est possible de bypass le filtre avec {{{7*7}}} form

On essaye la fameuse payload : {{self.__init__.__globals__.__builtins__.__import__('os').popen('id').read()}}

Ehhh bah non. form

Il reste donc encore quelques filtres à bypass. Pour trouver quels caractères sont filtrés on passe **{{import os global[]'.()"_ }}** en titre.

On obtient заглавие : {import os global'()" }. Les caratères []._ sont donc filtrés

Notre payload final :

form

On a bien notre reverse shell.

form

Step 2 : Crontab & notify for the win

Après énumération du serveur on remarque :

  • /root/.config/notify est accessible en lecture et écriture.
  • /etc/cron.d/job-cron inaccessible en lecture.

Ne pouvant pas accéder au crontab il nous faut trouver un moyen de voir ce qu’il se passe sur la machine. Nous pouvons utiliser pspy pour voir les processus en cours d’executions.

form

Voilà on recupère le crontab :). On comprend que le flag est pipe vers notify.

Après quelques recherches on trouve le repo github de notify. Ce tool permet de transmettre le résultat d’une commande sur différentes plateformes tel que discord, telegram …

Il ne nous reste plus qu'à configurer notre provider-config.yaml avec notre webhook discord, situé dans /root/.config/notify.

form

On attend que le crontab soit exécuté.

form