CactusCon9 - Scénario Take Back C0ntrol - Challenges Web


Sommaire

1/ CactusCon9

2/ tl;dr - Take Back C0ntrol

3/ Flag 0x01

3.1/ XSS

3.2/ Défaut de contrôle d’accès

4/ Flag 0x02

4.1/ LFI

5/ Flag 0x03

5.1/ MySQL SSRF

6/ Flag 0x04

6.1/ Flask SSRF

7/ The End

CactusCon9

C’est la première fois que je découvre la CactusCon, une conférence réalisée en ligne (forcément en ce moment :]) accompagnée d’un CTF d’une durée de 7h, les challenges restent par la suite accessibles le temps de la conférence.

Les vidéos des différents talks de la CactusCon9 sont accessibles sur Youtube et je ne peux qu’en recommander la visualisation.

Je souhaitais revenir sur l’un des scénarios présents au sein du CTF qui m’a plu. Je suis également le seul participant a avoir complété ce scénario, c’est pourquoi je me devais de faire un write-up sur la réalisation de ce dernier.

tl;dr - Take Back C0ntrol

Le scénario s’articule autour de 4 challenges Web, le chemin de résolution attendu lors de l’étape 1 est l’exploitation d’une injection XSS à l’aveugle. Malheureusement, les charges soumises au bot admin ont neutralisé la réalisation de cette étape pour les autres participants :(

J’ai donc profité d’un défaut de contrôle d’accès pour prendre le contrôle du compte admin et continué ainsi le challenge. Les autres étapes s’appuient sur l’exploitation d’une SSRF à travers le chargement d’un fichier CSV distant. Il est demandé de réaliser une LFI triviale, puis d’abuser d’une base de données MySQL non protégée et d’une API Flask authentifiée.

Flag 0x01

L’application présente une mire d’authentification et un formulaire de création de comptes. Ce dernier comporte un nom, un email et un message (ces champs sont vulnérables à l’exploitation d’une injection XSS à l’aveugle sur le panel d’administration). L’application est exposée sur 167.172.18.80:8888.

XSS

J’ai commencé ce challenge assez tôt dans le CTF. Il était possible de réaliser une injection XSS et d’obtenir des informations sur la provenance de l’administrateur via le Referer (10.10.10.52/_admin_users_management.php).

Néanmoins, je me suis arrêté assez vite sur la réalisation du challenge.

Le lendemain, je constatais qu’il n’était plus possible de forcer l’administrateur à venir récupérer la charge malveillante sur mon VPS. J’en ai rapidement déduit que le bot en charge de vérifier les payloads XSS étaient probablement en souffrance à cause des nombreuses charges qu’il a déjà essuyées depuis le début du CTF.

Défaut de contrôle d’accès

Je décide d’accéder directement au script identifié dans le Referer bien que l’IP exposée diffère de l’IP du bot (ce n’est peut-être qu’une simple question d’interface réseau).

Il apparaît que le fichier existe et n’applique aucun contrôle d’accès ! Il est donc possible d’obtenir le mot de passe de l’administrateur par ce biais et de constater que les charges XSS envoyées sur cette page redirige constamment vers divers sites Web. Il n’est donc plus envisageable pour les autres participants de réussir le challenge par le biais d’une XSS à moins de redémarrer le challenge (chose qui n’a pas été faite car ceci a été constaté au-delà des 7h du CTF).

admin_password

En me connectant sur l’application en tant qu’administrateur, je constate qu’il est possible d’accéder à la fonctionnalité d’import et de configuration de l’application. La configuration n’est pas altérable et laisse suggérer que des services internes pourront être joints par la suite. De plus, des messages sont présents dans la boîte de réception du compte d’administrateur et font également références à ces services.

ssrf_targets

messages

La fonctionnalité d’import semble tenter de charger un fichier CSV dont les colonnes sont spécifiées dans le message d’erreur :

csv_import

La requête associée est un POST avec l’URL soumise et la fonctionnalité choisie (import).

Ne disposant pas d’un accès aux autres fonctionnalités telles que l’export je modifie la fonctionnalité d’import par export et obtiens le premier flag bien que cela n’apporte aucune fonctionnalité complémentaire :

flag1

flag{m0r3_th4n_ju57_4l3rt5}

Le contenu du flag suggère également que la compromission attendue s’appuie sur l’injection XSS.

Flag 0x02

La suite du challenge va donc se concentrer sur l’exploitation de la fonctionnalité d’import.

LFI

Après avoir crée un fichier CSV contenant les colonnes nécessaires sur mon VPS, j’ai pu constater une SSRF au sein de la colonne catalogURL. La description du second challenge indiquait la nécessité de récupérer le contenu du fichier /flag (merci de la précision, cela évite une phase de guessing potentiellement fastidieuse…).

ssrf_to_lfi

Le contenu renvoyé après la réalisation de la SSRF est en Base64.

flag{an_error_of_thinking}

Flag 0x03

Il est maintenant temps de s’attarder sur les différents services configurés sur l’application (Memcached, MySQL, Elasticsearch, Flask). L’exploitation de la SSRF sur les services Memcached et Elasticsearch n’a pas permis d’avancer davantage dans la résolution du challenge, je n’en parlerai donc pas.

MySQL SSRF

D’après les messages dans la boîte de réception, l’accès à la base de données MySQL n’est pas protégée par un mot de passe. Il est donc largement envisageable de compromettre cette dernière par le biais d’une SSRF. La petite subtilité ? Ce n’est pas le compte root qui n’est pas protégée mais celui de brian, je n’avais pas relevé ce point. Après avoir essayé divers moyens d’accéder au service MySQL (y compris via la recherche d’une SSRF intermédiaire sur Memcached ou Elasticsearch afin de provenir de 10.10.10.53 - localhost plutôt que 10.10.10.52), j’ai demandé au créateur du challenge si c’était normal ou si le challenge était “cassé”. Ce dernier m’a alors indiqué de prêter attention à l’utilisateur spécifié dans le message.

Effectivement le compte de brian ne dispose pas de mot de passe, il est donc possible d’intéragir avec la base de données. Pour cela, je me suis appuyé sur Gopherus.

Un exemple de génération d’une payload via Gopherus sur le service MySQL :

gopherus_payload_generation

Cette payload est à insérer comme ci-dessous au sein d’un fichier CSV distant :

gopherus_payload_in_csv

Après exploitation de la SSRF, on obtient enfin les informations que l’on cherche :

gopherus_show_databases

On découvre ensuite une table “settings” au sein de la base de données “webnote”. La récupération du contenu de cette dernière nous donne le flag et ce qui semble être une clé d’API :

gopherus_flag3

flag{c0ntr0l_i5_4n_illusi0n}

Flag 0x04

La dernière partie est relative au dernier message de la boîte de réception sur un service Web entre les ports 6600 et 6700.

Flask SSRF

Après avoir générée un fichier CSV par port sur l’IP du service Flask (10.10.10.54), j’ai réalisé un bruteforce via patator. Rapidement, je découvre que le port 6666 renvoie de la donnée :

flag4_csv_generation

flag4_patator

Le service renvoie systématiquement la réponse suivante :

flag4_initial_http_request

flag4_initial_http_response

Il est spécifié dans le message de la boîte de reception qu’un en-tête HTTP x-apikey est requis, cela fait sens.

Nous avons récupéré au sein de la base de données MySQL une clé d’API MYSECRETAPIKEY. Le dernier petit tricks pour obtenir le flag est ensuite de forger une SSRF via le protocole gopher afin d’inclure une requête HTTP avec les en-têtes associés.

En effet, la simple utilisation du protocole HTTP ne permettra pas de rajouter des en-têtes à la volée lors de la réalisation de la SSRF.

La payload finale au sein du CSV distant est donc :

flag4_api_payload

Une fois la réponse décodée du service Flask on obtient le dernier flag :

flag4_flask

flag{but_50m3tim3s_Y0u_Need_1llusi0n}

The End

J’ai éprouvé quelques difficultés complémentaires sur le dernier flag car je pensais que la clé d’API était le flag3 alors qu’il s’agissait simplement de de la clé évoquée précedemment. Je testais alors des variations d’en-têtes permettant de réaliser une authentification d’API, sans succès. Ryan (l’auteur du challenge) m’a indiqué que je faisais fausse route, merci à lui pour son aide et le challenge proposé. J’ai particulièrement apprécié l’exploitation des différents services via la SSRF.

Merci aux organisateurs de la CactusCon9 !

ECSC - Préqualifications - Challenges Web