PICOCTF 2017 – CRYPTO LVL 02 – SoRandom – Write-up

Dans cet article, je vais exposer la solution à l’un des challenges du PicoCTF 2017, un CTF en ligne qui a eu lieu durant une quinzaine de jours début avril.

Il s’agit d’un challenge de niveau basic/intermédiaire de la partie Crypto. Le challenge se nomme “SoRandom“.

Le challenge est constitué d’un flag “BNZQ:8o149b15764q471k2533971t6w78liec” et d’un script python, qui a manifestement été utilisé pour générer le flag. Le but du challenge est de comprendre comment le script fonctionne et de l’utiliser ensuite pour retrouver le message en clair.

Voici le contenu du script récupéré

On voit donc ici que pour chaque caractère du flag, une opération consistant à modifier ce caractère par un autre est effectuée. Chaque opération semble différente en fonction de s’il s’agit d’une majuscule, d’une minuscule, d’un chiffre ou autre.

L’opération consiste précisément à faire varier la valeur ASCII du caractère (on peut le repérer via les fonctions “ord”, qui permet de convertir un caractère en son équivalent décimal ASCII et “char” qui permet de convertir un décimal en caractère en suivant ce tableau.

Tableau ASCII

Tableau ASCII

Une autre spécificité intéressante est l’utilisation de “random.seed”

random.seed("random")

Après quelques recherches (http://stackoverflow.com/questions/22639587/random-seed-what-does-it-do), j’apprends que l’utilisation de random.seed permet de gérer l’aléatoire. Plus précisément, en utilisant random.seed, l’aléatoire prendra comme source de départ la chaine indiquée (“random”) et la suite aléatoire générée sera ensuite toujours la même.

On peut ainsi récupérer la chaine aléatoire utilisée pour “dériver” chaque caractère en modifiant le script de la façon suivante :

Voici le résultat obtenu.

Pour chaque caractère, on récupère le nombre aléatoire utilisé pour calculer le caractère “chifrré” correspondant. De cette façon, la seule inconnu qui pouvait poser problème dans chaque dérivation est maintenant connue. Chaque caractère de la chaine chiffrée correspond à un caractère de la chaine aléatoire trouvée.

Je modifie donc le script pour brute forcer chaque caractère du flag “chiffré” avec la reflexion suivante :

  1. Faire une boucle pour chaque caractère de la chaine de caractère aléatoire;
  2. Pour chaque caractère, prendre le caractère correspondant de la chaine chiffré (position dans la chaine de caractère);
  3. Faire un brute force de chaque caractère de la catégorie correspondante (majuscule, minuscule ou chiffre);
  4. Si je parviens à retrouver le caractère du chiffré en appliquant la formule mathématique, c’est que le caractère testé au départ est le bon (parmis tous les caractères testés lors du brute force);
  5. Puis je passe au caractère suivant.

Pour avoir une idée plus claire de cette logique, voici le code python que j’ai utilisé pour retrouver le flag.

En fonction de si le caractère est une majuscule, minuscule ou un chiffre, j’applique la formule mathématique présente dans le script de chiffrement utilisé, sauf que je brute force les possibilités unes à unes pour retrouver la bonne.

Le seul piège que j’ai eu à contourner, outre la construction de la logique que je viens d’exposer, et de supprimer le “:” du flag lors de l’application de la chaine aléatoire. En effet, on remarque que lorsque la boucle arrive sur “:”, aucun seed correspondant n’est appliqué. Je pense que ceux qui ont tenté de résoudre ce challenge on également vu ce petit piège.

Vous aimerez aussi...

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *