CTF – IMF 1

novembre 10, 2016

Sorti il y a quelques jours à peine,  nous allons nous attaquer cette fois à la VM / Capture The Flag IMF 1 de Geckom (Twitter: @g3ck0m).  Le but est de récupérer un ensemble de flags. Chaque flag nous permet d’avoir un indice vers le flag suivant, la difficulté est croissante.

La VM (1.6 GB) est téléchargeable directement sur le site vulnhub.com / imf

un rapide : nmap 192.168.211.0/24 -sP m’indique que l’ip de notre cible est la 192.168.211.139.

En regardant plus en détail  : nmap 192.168.211.139 -PN -O -sV -p 1-65535

Seul le port 80 semble ouvert :

imf_ctf2

Flag 1 :

Le premier Flag ne pose pas de difficulté, il suffit simplement d’afficher le code source de la page ‘contact_us’ :

imf_ctf3

Flag 2 :

L’indice laissé par le premier flag nous suggère de regarder tous les fichiers. En observant le code source je remarque ceci :

imf_ctf4

La concaténation de noms des .JS donne :

ZmxhZzJ7YVcxbVlXUnRhVzVwYzNSeVlYUnZjZz09fQ==

Flag 3 :

Rendez vous donc dans le rep : http://192.168.211.139/imfadministrator

imf_ctf5

le code source nous indique :

En faisant quelques tests je remarque que dans ce formulaire d’authentification, la vérification du Username semble fonctionner. En me basant sur les utilisateurs indiqués dans la page contact-us j’arrive à obtenir un message d’erreur différent :

En recherchant comment bypass l’authentification, je suis tombé sur un article intéressant relatif à l’instruction PHP strcmp():
http://danuxx.blogspot.fr/2013/03/unauthorized-access-bypassing-php-strcmp.html

L’auteur y explique qu’au lieu de traiter l’entrée HTTP sous forme de chaînes simples, PHP va construire des tableaux de données par requête HTTP. Cela pouvant conduire à la confusion au sujet des données et peut facilement conduire à des bogues de sécurité.

L’objectif est de trouver un moyen pour forcer strcmp à nous renvoyer 0 sans même connaitre le mot de passe.
En fouillant sur différents sites, j’apprends que lorsqu’on envoie en PHP un tableau à comparer avec une string via la fonction strcmp() ou strcasecmp() alors cela renvoie 0.

Prenons l’exemple suivant fourni sur http://danuxx.blogspot.fr :

Si au lieu d’envoyer « &ps=a » j’envoie également les crochets [] dans le paramètre, un objet tableau sera alors envoyé et les deux valeurs seront égales !
Burp suite devrait pouvoir nous aider ! : user=rmichaels&pass[]=test

imf_burp

Flag 4  :

En continuant vers le CMS je pensais pouvoir uploader un fichier, mais malheureusement le site est encore en construction. Cependant il semble être vulnérable à une injection SQL.
 »
Warning: mysqli_fetch_row() expects parameter 1 to be mysqli_result, boolean given in /var/www/html/imfadministrator/cms.php on line 29 »

imf_sql

Un lien vers une image ‘whiteboard.jpg’ est indiqué dans la base de données. Récupérons l’image.

whiteboard

Une analyse via le site : https://zxing.org/w/decode.jspx nous indique :

imf_qrcode

Flag 5 :

Nous voilà désormais face à un formulaire d’upload  :

http://192.168.211.139/imfadministrator/uploadr942.php

J’ai tenté sans succès d’uploader directement un fichier php et de modifier le content type, ou encore double extension et null byte, mais systématiquement il me mettait une erreur, ou une restriction, dès que je passais le contrôle de l’extension, il vérifiait le contenu du fichier et systématiquement me refoulait dès qu’il trouvait les instructions PHP suivantes (sauf pour backsticks):

Via l’outil ‘weevely’ j’ai donc généré une backdoor.php.

imf_weevelybackdoor

Ensuite j’ai renommé cette backdoor en .GIF et j’ai indiqué en tête du fichier, la valeur hexadécimale du header du format gif : GIF89a34444

imf_backdoor

Une fois uploadée, j’ai regardé le code source afin d’en apprendre sur son répertoire de stockage et j’ai pu l’exécuter via weevely.

 

imf_weevely2png

 

imf_weevely3

 

En faisant un ls -al dans le répertoire courant,  il m’indique le nom d’un fichier intéressant = uploads/flag5_abc123def.txt

Flag 6 :

Afin d’en apprendre d’avantage sur l’indice laissé par le flag précédent : ‘agentservice’, j’ai commencé à rechercher des informations :

‘agent service’ est un exécutable en écoute sur la machine. Cependant le port semble filtré, impossible d’y accéder de l’extérieur :

Dans le répertoire /usr/local/bin j’y trouve également un fichier ‘acces_codes’ contenant des informations :

Il m’a fallu pas mal de temps avant de comprendre, ce fichier fait référence aux codes d’un port knocking, c’est à dire une méthode permettant de modifier le comportement d’un firewall en temps réel pour provoquer l’ouverture d’un port suite au lancement préalable d’une suite de connexions sur des ports distincts dans le bon ordre, à l’instar d’un code frappé à une porte.

Cette suite de chiffres correspondrait à un code qu’il faudrait taper dans l’ordre indiqué, afin de pouvoir accéder à l’application ‘agent service’ depuis l’extérieur :

Magique ! :) notre port 7788 est désormais ouvert pour l’extérieur :)
Ensuite j’ai récupéré l’exécutable ‘agent’ via weevely afin de l’analyser sur ma machine.

Commençons par un petit tour sur https://retdec.com/

imf_rec

La valeur correspondant à l’ID AGENT semble être codée en dur : 0x2ddd984, soit 48093572

Bingo ! voyons maintenant le menu de l’application. Le choix 3 nous permet d’insérer des caractères. Peut-être possibilité de Buffer OverFlow ? gdb devrait nous le dire :

imf_pattern_create

imf_pattern_offset

Nous écrasons EIP à 168 bytes et notre shellcode semble être à EAX. Préparons notre payload via msfvenom :

Il n’y a plus qu’à le mettre dans un script python que nous pourrons directement lancer :

imf_end

Mission accomplie ! Excellent CTF