Skip to main content

Fetch the Flag CTF 2022 : solution de Juggalo Central

Écrit par

Alexander Kraev

feature ctf juggalo central

10 novembre 2022

0 minutes de lecture

Merci d’avoir joué à Fetch avec nous ! Félicitations aux milliers de joueurs qui nous ont rejoints pourFetch the Flag CTF. Et un immense merci aux Snykers qui ont créé, testé et documenté les défis !

Si vous avez participé à l’édition 2022 de Fetch the Flag de Snyk et n’avez pas réussi à terminer le défi Juggalo Central, vous êtes au bon endroit. Découvrons ensemble la solution !

Guide pas à pas

Pour commencer, un lien mène à un site web contenant le formulaire de connexion habituel, avec deux champs : nom d’utilisateur et mot de passe. Il y a aussi un fichier avec une extension .php. Commençons par examiner le site web.

Le site web

Comme indiqué précédemment, la page comporte deux champs de saisie (et une image de clown). J’ai d’abord vérifié le code source de la page, le fichier .css et même l’image. Rien d’exploitable. J’ai remarqué qu’il y avait deux messages d’erreur différents : l’un lorsque j’utilisais un nom d’utilisateur courant comme « admin », et l’autre lorsque j’entrais une chaîne aléatoire comme « qweasdzxc ».

Le code

Dans index.php, j’ai trouvé trois fonctions : getFlag, searchUserByName et validateCredentails.

La première fonction, getFlag, interroge une table de base de données appelée flag et renvoie la toute première ligne trouvée. Après quelques calculs, j’en ai conclu que la clé recherchée était stockée dans cette table.

La deuxième fonction, searchUserByName, cherche un utilisateur à partir de la variable d’entrée appelée $username. Si des résultats sont trouvés, la fonction les renvoie. J’ai remarqué cette ligne :

     return $stmt->fetchAll(PDO::FETCH_ASSOC);

Cela signifie que cette fonction ne renverrait pas forcément une seule ligne (je m’attends à ce que les utilisateurs aient des noms d’utilisateur uniques) : s’il existe plusieurs utilisateurs portant le même nom, elle les renverra tous. J’ai découvert par la suite que cela ne nous serait pas utile, à cause de ce qui se passe dans la fonction suivante. Ça arrive parfois dans un CTF.

La troisième fonction, validateCredentails, lit le nom d’utilisateur et le mot de passe transmis dans le corps de la requête POST, puis appelle searchUserByName pour vérifier s’il existe un utilisateur portant ce nom. J’ai également compris pourquoi le message d’erreur était différent pour un nom d’utilisateur composé de caractères aléatoires. Si le nom d’utilisateur fourni n’existe pas, la fonction renvoie : « Juggalo not found! ». En revanche, pour tout nom d’utilisateur existant associé à un mot de passe incorrect, le message d’erreur est : « Invalid credalo ».

Trouver un nom d’utilisateur valide

Nous allons maintenant chercher des identifiants valides. Lorsque j’ai essayé un nom courant comme « admin », j’ai obtenu le message d’erreur « Invalid credalo ». Grâce à l’analyse du code effectuée à l’étape précédente, je peux maintenant affirmer qu’un utilisateur possède la valeur « admin » dans son champ de nom d’utilisateur.

Première hypothèse

Maintenant que nous avons un nom d’utilisateur valide, voyons comment pirater le mot de passe. Le message d’erreur indiquant que nous n’avons pas accès à cet utilisateur est dû à la ligne de code suivante :

    if ($results[0]['password'] != substr(md5($username . $password), 0, 20)) {

À gauche de la condition, le mot de passe de l’utilisateur est récupéré dans la base de données. À droite, on trouve les 20 premiers caractères du hachage md5 calculé à partir de deux variables fournies par l’utilisateur : username et password.

Ma première idée était que cette condition impliquait que tout mot de passe valide devait être une chaîne de 20 caractères. En bref, je me trompais.

Deuxième hypothèse

Après avoir réfléchi un moment au défi, une autre idée m’est venue. Cette ligne utilise l’opérateur de comparaison !=. Je suis donc allé consulter la documentation officielle de PHP pour vérifier le fonctionnement des opérateurs de comparaison dans PHP. Une phrase de la documentation, juste à côté de l’opérateur !=, m’a laissé perplexe :

true if $a is not equal to $b after type juggling.

Attendez. Qu’est-ce que la « coercition de type » ? Après avoir lu cela, j’ai rouvert la page web du défi. Le clown était toujours là, à me regarder.

Le piratage

Il existe en fait en PHP un mécanisme appelé « coercition de type ». Après avoir lu un article sur le sujet et exécuté quelques tests PHP en ligne, j’ai trouvé la condition suivante :

    if ("0" == "0e12345")

Étonnamment, cela a renvoyé « true ». Cela s’explique par le fait que PHP convertit les deux opérandes en valeurs numériques. Pour trouver le bon mot de passe de l’utilisateur « admin », il nous suffit maintenant de générer un hachage md5 qui répond à deux conditions : commencer par « 0e » et ne contenir que des chiffres ensuite (ou au moins 18 caractères après, en raison de l’utilisation de substr).

Le script

Voici un script Python qui permet de trouver le bon hachage :

import hashlib

target = '0e'
candidate = 0;
while True:
   plaintext = 'admin'+target+str(candidate)
   hash = hashlib.md5(plaintext.encode('ascii')).hexdigest()
   # Hash starts with “0e”
   if hash[:2] == target:
       # Hash contains only one letter (“e”) in first twenty characters
       # So it can be considered as a number by PHP
       if sum(c.isalpha() for c in hash[:20]) == 1:
           print('username and password:' + plaintext);
           break
   candidate = candidate + 1

Au bout d’une minute, j’ai pu me connecter à la page web Juggalo Central avec les identifiants générés par ce script.

Autres solutions de Fetch the Flag

Vous voulez savoir comment nous avons trouvé tous les autres flags ? Consultez notre page Solutions de Fetch the Flag pour découvrir notre démarche.

Lire la suite

Blog

Les modèles de pointe ont trouvé les vulnérabilités. Seul l’attaquant a trouvé les chaînes d’exploitation.

L’analyse statique a détecté les failles, mais seuls des tests d’attaque en conditions réelles ont prouvé comment elles pouvaient être enchaînées pour provoquer des compromissions. Comparaison d’Evo COS, de Claude Security et de Claude Code Security.

feature insights context
Blog

Les attaques autonomes sont déjà là. La défense doit suivre leur rythme.

Les attaquants autonomes réduisent la fenêtre de défense. Découvrez comment la découverte, la correction, la validation et la prévention continues peuvent aider les équipes de sécurité à suivre le rythme.

Blog

Pourquoi les agents de codage IA créent-ils sans cesse des failles de contrôle d’accès ?

Les agents de codage IA peuvent générer une logique d’autorisation qui compile et passe la revue, tout en exposant les données d’un tenant à un autre. Découvrez pourquoi les failles de contrôle d’accès sont difficiles à détecter et comment les prévenir.