3 minutes
[Midnightflag] BGK Writeup
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.
Step 1 : Exploitation d’un cookie flask
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.
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.
On peut alors essayer de decoder le cookie avec flask-unsign.
Essayons maintenant de bruteforcer la clé permettant de signer le cookie.
Bingo ! on obtient la secret key : coldwar.
On peut maintenant modifier le champ user_id de notre cookie pour lui attribuer la valeur 1.
Nous pouvons maintenant utiliser le cookie pour obtenir une session admin et accéder à la page /scan.
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.
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 …
On peut essayer de modifier le titre de notre serveur web en plaçant par exemple {{7*7}}.
Le titre est filtré, nous obtenons {7*7}.
Il est possible de bypass le filtre avec {{{7*7}}}
On essaye la fameuse payload : {{self.__init__.__globals__.__builtins__.__import__('os').popen('id').read()}}
Ehhh bah non.
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 :
On a bien notre reverse shell.
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.
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.
On attend que le crontab soit exécuté.