piątek, 17 października 2025

picoCTF - hashcrack

W tym poście opiszę rozwiązanie zadania Hashcrack z picoCTF. 


Hash jest wynikiem działania funkcji matematycznej która przekształca dane wejściowe w ciąg o stałej długości. Wprowadzenie małej zmiany w danych wejściowych spowoduje kompletną zmianę wyniku. 

Stosuje się ją do weryfikacji integralności danych. Na przykład weźmy jakiś plik konfiguracyjny w systemie, czy dane z pamięci. Jeśli na danych wykonamy zmianę i ktoś je zmodyfikuje bez aktualizacji hash'a np. ręcznie bądź przez jakiś błąd. To po odczycie i weryfikacji będziemy w stanie stwierdzić, że dane zostały zmienione w niezatwierdzony przez programistę/administratora sposób. 

Inne zastosowanie to przechowywanie haseł w bazie danych jako hash. Przy logowaniu do konta użytkownik wpisuje swoje hasło. Z tego hasła wyliczany jest hash i następuje porównanie z hashem z bazy danych, a nie bezpośrednio z hasłem. Jeśli ktoś uzyska dostęp do bazy danych to nie będzie mógł odzyskać haseł bezpośrednio. Wynika to z faktu, że hash jest jednostronny. Jest praktycznie niemożliwe by z hash'a odtworzyć wynik. Zamiast tego stosuje się porównywanie wygenerowanych hashów przy próbach złamania haseł. Z tego powodu trudne hasło znacznie wydłuża bądź całkowicie uniemożliwia taki proces. 

Wyróżnia się następujące funkcje hashujące:
MD5, SHA-1 - nie zalecane. 
SHA-256, SHA-512 - powszechnie stosowane. Uznane za bezpieczne. 

Jedną ze wskazówek do zadania jest zapoznanie się z plikiem rockyou.txt (można znaleźć np. na githubie).


Zawiera on gigantyczną listę powszechnie używanych haseł. Można go użyć do przygotowania programu, który będzie tworzył hash z tekstów i porównywał z szukanym ciągiem. 

Wszystkie hasła wykorzystane w tym zadaniu znajdują się na tej liście. 

Po uruchomieniu zadania dostajemy następującą informacje:


Dostaliśmy hash i musimy na jego podstawie odgadnąć hasło:

  1. 482c811da5d5b4bc6d497ffa98491e38
 
Hash ma długość 32 znaków. Z tego powodu można zakładać, że jest to MD5. Co potwierdzamy na stronie (link https://hashes.com/en/tools/hash_identifier):


W celu odzyskania danych z takiego hash'a, najprościej, posłużyć się stroną internetową, która po wgraniu danych wydrukuje poprawną odpowiedź (link: https://crackstation.net/):

W celu weryfikacji można sprawdzić jak wygląda hash dla password123: 

  1. import hashlib
  2. print(hashlib.md5(b"password123").hexdigest())

Można też odrobinę rozbudować ten program i porównywać dane z szukanym hashem:

  1. import hashlib
  2.  
  3. # Lista potencjalnych haseł
  4. passwords = [
  5.     "123456",
  6.     "password",
  7.     "pass",
  8.     "password123",
  9.     "tset123",
  10.     "test4566"
  11. ]
  12.  
  13. target_hash = "482c811da5d5b4bc6d497ffa98491e38"
  14.  
  15. for pass_d in passwords:
  16.     hashed = hashlib.md5(pass_d.encode()).hexdigest()
  17.     if hashed == target_hash:
  18.         print(f"Znaleziono hasło: {pass_d}")
  19.         break
  20. else:
  21.     print("Nie znaleziono pasującego hasła")
Po wprowadzeniu hasła przechodzimy do następnego:


Tym razem jest to SHA-1. Długość 40 znaków. 


Wracamy na stronę crackstation:


Po wprowadzeniu hasła dostajemy kolejnego hash'a tym razem są to 64 znaki, czyli SHA-256:


Znowu crackstation:


Dla testu wygenerowałem trudne hasło leHowtWfkdWkNPXL. Z niego wygenerowałem hash SHA-256

48ebcae188291687c08beaf0a15b98a8576569ca701ddaefd13845e28d7b1b79

Wrzuciłem go na stronę crackstation:


Tym razem nie poradził sobie z zadaniem. Jak widać każdy z hashów jest możliwy do złamania jeśli wykorzystywane są przewidywalne ciągi znaków. 

Jak już mamy wszystkie hasła to otrzymujemy pełne rozwiązanie:


Teraz można wprowadzić flagę i zakończyć zadanie.