team-logo
Published on

NahamCon CTF 2025 - Reverse - FlagsFlagsFlags

Authors

Introduction

Flags

There were two approaches to this task. One was to dig in and analyze the code, and the other was classic bruteforce. This task was written in Rust, and these binaries are hard to analyze, so I chose bruteforce. But classic bruteforce would take a long time. there were 100,000 flags to check, so I assisted with 100 threads. Threads in current Python don't always speed things up. In this case, however, they helped.

Extract flags from binary 1

strings flagsflagsflags > input.txt

Extract flags from binary 2

import re
counter=1
def extract_flags(input_file, output_file):
    # Odczytanie zawartości pliku
    with open(input_file, 'r') as file:
        content = file.read()
    
    # Znajdowanie wszystkich flag za pomocą wyrażenia regularnego
    flags = re.findall(r'flag\{[0-9a-f]{32}\}', content)
    #counter=+1
    #print (counter)
    # Zapisanie flag do nowego pliku, każda w nowej linii
    with open(output_file, 'w') as file:
        for flag in flags:
            file.write(flag + '\n')

# Wywołanie funkcji
input_file = 'input.txt'  # Nazwa pliku wejściowego
output_file = 'flags.txt'  # Nazwa pliku wyjściowego
extract_flags(input_file, output_file)

Bruteforce Solution

from pwn import *
import threading
import os

BINARY_NAME = "./flagsflagsflags"
FLAG_FILE = "flags.txt"


# Sprawdzenie pliku
if not os.path.isfile(FLAG_FILE):
    print(f"Błąd: Nie znaleziono pliku {FLAG_FILE}!")
    exit(1)

# Wczytanie flag
with open(FLAG_FILE, 'r') as f:
    flags = [line.strip() for line in f.readlines()]

# Zmienne współdzielone
results = []
lock = threading.Lock()
found_flag = threading.Event()
licznik=0
def worker(flag_chunk, thread_id):
    for flag in flag_chunk:
        if found_flag.is_set():  # Przerwij jeśli znaleziono flagę
            return
        global licznik
        #print ("Watek nr: ",thread_id)    
        context.log_level = 'warning'        #tutaj potrzebne, bo inaczej smieci
        licznik += 1
        if licznik % 1000 == 0:
            print(f"Wątek {thread_id}: Sprawdzono {licznik} flag...")
       
            #warning (licznik)
        
        try:            
            p = process(BINARY_NAME)
            p.sendlineafter(b'Enter the flag', flag.encode())
            output = p.recvall(timeout=2)            
            p.close()
            

            if b"Incorrect flag!" not in output:            
                with lock:
                    results.append(flag)
                    print(f"Wątek {thread_id}: Znaleziono poprawną flagę -> {flag}")
                    found_flag.set()  # Powiadom inne wątki
                    
        except Exception as e:
            with lock:
                print(f"Wątek {thread_id}: Błąd dla flagi {flag} - {str(e)}")

# Podział pracy
num_threads = 100
chunk_size = len(flags) // num_threads
threads = []

for i in range(num_threads):
    start = i * chunk_size
    end = start + chunk_size if i < num_threads - 1 else len(flags)
    t = threading.Thread(target=worker, args=(flags[start:end], i))
    threads.append(t)
    t.start()

# Czekaj na zakończenie
for t in threads:
    t.join()

# Podsumowanie
print("\nZnalezione poprawne flagi:")
for flag in results:
    print(flag)
flag{20dec9363618a397e9b2a0bf5a35b2e3}