BreizhCTF 2018

26 Avr 2018
Marc Lebrun
533
0

L’équipe pentest de Digitemis était présente pour la première fois au BreizhCTF. Cette édition était encore une fois organisée et animée par SaxX et Kaluche, mais cette fois sur le campus de Beaulieu de l’université de Rennes.

Nous vous proposons de revenir sur l’évènement au travers d’un court write-up de quelques challenges choisis.

BabySys – Baby – 50 pts

« BabySys » est un challenge permettant d’exploiter une vulnérabilité contenue dans un script système.

Le service utilise le programme « Cowsay », écrit en Perl, qui permet d’afficher une vache en ASCII indiquant le message que l’utilisateur lui fournit.

Le script inclus 3 fonctions différentes :

  • La première permet d’afficher une bulle vide au-dessus de la vache
  • La deuxième permet l’affichage de l’heure et de la date
  • La troisième affiche une valeur fournie en paramètre par l’utilisateur
  • La dernière permet de quitter le programme

Nous allons nous arrêter sur la troisième fonction étant donné qu’il s’agit de la seule fonction où l’on peut saisir ce que nous voulons. Dans un programme Bash, il est possible d’exécuter une commande dans une variable à l’aide de l’instruction $(<commande>). Afin d’obtenir l’endroit où est stocké le flag, on affiche le contenu du répertoire courant.

On obtient donc deux fichiers : « cowoc » et « flag ». Le premier étant certainement le programme en lui-même, nous affichons le contenu du second avec un « $(cat flag) » et obtenons le flag !

Grid2 – Crypto – 50 pts

Le challenge de Crypto « Grid2 » est tiré d’un challenge de la nuit du hack 2016 intitulé « Grid ». Pour ceux qui ne connaissent pas le challenge originel, un write-up est disponible ici.
Lorsque nous nous connectons à l’adresse indiquée, nous avons un site affichant un test de couleurs arc-en-ciel et en rotation permanente.

Inutile de rester plus longtemps sur cette page (risque de crise d’épilepsie sur le long terme), nous affichons donc la source de cette dernière.

 

Le « body » contient deux éléments intéressants : la balise « h2 » et la classe « rainbow ». En observant le challenge cité précédemment, on devine que le premier élément correspond à l’index et que le deuxième correspond à un tableau de données. Nous séparons les deux éléments en deux fichiers « grid2_index » et « grid2_data ».
Chaque paire de coordonnées (ex : « 013:009 ») est séparée par ligne dans le fichier « grid2_index ».

Il faut alors créer un script (en bash bien sûr <3) permettant de parcourir l’index et utiliser les coordonnées afin d’extraire les données souhaitées.

Here is the flag : bzhctf{B35t_ndh_ch4ll_3v3r !

Vous remarquerez qu’il manque l’accolade fermante (« } ») à la fin du flag. Il s’agit ni plus ni moins d’une erreur dans les dernières coordonnées qui ont été fournies pour réaliser le challenge. En remplaçant « 012:020 » en « 012:010 », on obtient le flag complet : bzhctf{B35t_ndh_ch4ll_3v3r}

Flag In Hell – Misc – 75 pts

Dans ce challenge, on récupère un fichier dont on ne peut distinguer le type. Après inspection avec hexdump -C fichier | tail -n 8, on reconnaît le header d’un certain type de fichier avec « GNP » et « TADI » => « PNG IDAT ».

A priori le fichier est à l’envers octet par octet.
On va reconstruire l’image à partir d’une one liner « cause it tastes better »!

Nous disposons donc d’une image, mais cela ne suffit pour résoudre le challenge.

On va donc procéder à une inspection basique de l’image avec exiftool:

Ici, il faut prêter attention au message d’erreur renvoyé par exiftool, il suggère que des données sont présentes après la zone normalement prévue à cet effet.

L’image ne semble pas être suffisamment grande, nous allons la redimensionner avec l’outil « TweakPNG » en 1200×1600. Une fois redimensionnée, l’image nous donne le flag 🙂

Basique simple simple basique – Web – 100 pts

L’épreuve se présentait sous la forme d’un serveur web, exposant un message d’erreur relativement explicite lors du premier accès :


Il est donc nécessaire de faire croire au serveur que nous venons de localhost. Pour cela, nous utiliserons le header « X-Forwarded-For » avec la valeur 127.0.0.1 :


Le serveur répond alors en nous renvoyant un cookie de session :


Ainsi qu’une mire d’authentification :

Une rapide analyse de la valeur du cookie de session permet de donner une piste sur la façon de contourner l’authentification. En effet, le cookie de session est d’abord encodé en base64 :

Valeur en Base64Valeur en clair
ZmFsc2U2ODkzNGEzZTk0NTVmYTcyNDIwMjM3ZWIwNTkwMjMyNw%3D%3Dfalse68934a3e9455fa72420237eb05902327

On observe ensuite la présence d’un hash md5 à la suite de la valeur false. Il s’agit en réalité du hash md5 de la valeur « false » :

Valeur en clairValeur en MD5
false68934a3e9455fa72420237eb05902327

En modifiant la valeur du cookie de session par la suivante :

Valeur en Base64Valeur en clair
dHJ1ZWIzMjZiNTA2MmIyZjBlNjkwNDY4MTA3MTc1MzRjYjA5trueb326b5062b2f0e69046810717534cb09

Le serveur accepte notre requête, qu’importe les valeurs insérées dans les champs « Username » et « Password » :

Nous sommes alors redirigés vers une nouvelle page affichant le flag :

Desprecito – Mobile – 250 pts

Les challenges « mobile » étaient une nouveauté bienvenue de cette édition 2018. Pour le challenge Desprecito, une application Android était fournie au format APK. En la décompressant, on retrouve l’arborescence typique :

On peut déjà constater qu’un fichier enc.bin est présent dans le répertoire asset :

À première vue, des données Java sérialisées. La chaîne « DES/ECB/PKCS5padding » nous indique qu’elles sont probablement également chiffrées. Décompilons le code de l’application pour y voir plus clair. La première étape est de convertir le fichier classes.dex en classes Java :

À l’aide de son décompilateur favori (jd-gui ou jad par exemple), on retrouve le code d’origine. Il est par ailleurs plutôt lisible, aucune opération d’obfuscation ne semble avoir été appliquée :

Le programme est très simple, il s’agit d’un chiffreur prenant l’algorithme de chiffrement, le flag et le fichier de sortie en paramètre. La clef est générée au runtime et stockée dans un objet Data, le flag encapsulé dans un Sealed Object Java avant de rejoindre la clef dans l’objet Data.

En réimplémentant les opération inverses, on retrouvera aisément le flag :

  1. Charger le fichier
  2. Lire la clef de l’objet Data
  3. Déchiffrer le Sealed Object contenant le flag avec l’algorithme DES/ECB/PKCS5padding
  4. ???
  5. Profit !

Cryptonik – Mobile – 150 pts

Toujours dans la catégorie mobile, le challenge Cryptonik a été ouvert plus tard (très tard) dans la nuit. L’approche est la même, on commence par décompresser le fichier APK.

On constate encore la présence d’un fichier enc.bin dans le répertoire assets. On peut donc encore s’attendre à une épreuve de cryptographie.

Comme pour Desprecito, on décompile le code Java présente dans classes.dex :

À la lecture du code (qui n’est toujours pas obfusqué), on comprend que deux chaînes ont été chiffrées puis stockées dans une classe, elle-même sérialisée et posée sur le disque. L’une des deux chaînes est sans aucun doute le flag caviardé. La méthode encrypt() assure le chiffrement et itère autant de fois que nécessaire sur la clef en XORant les octets un à un.
La génération de la clef de 30 octets est réalisée par la méthode cryptonik_gen().

La classe Data est un objet des plus simples, deux variables pour les données chiffrées et des getters.

Connaissant l’une des deux chaînes et XOR étant une opération mathématique réversible, nous pouvons réaliser une attaque à texte clair connu (known-plaintext attack) pour retrouver la clef et déchiffrer le flag (en Java, pour le sport) :

 

Félicitations à toutes les équipes participantes et merci aux organisateurs pour cet évènement organisé avec brio dans une ambiance détendue. A l’année prochaine 😉