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).
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:
- 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:
- import hashlib
- print(hashlib.md5(b"password123").hexdigest())
Można też odrobinę rozbudować ten program i porównywać dane z szukanym hashem:
- import hashlib
- # Lista potencjalnych haseł
- passwords = [
- "123456",
- "password",
- "pass",
- "password123",
- "tset123",
- "test4566"
- ]
- target_hash = "482c811da5d5b4bc6d497ffa98491e38"
- for pass_d in passwords:
- hashed = hashlib.md5(pass_d.encode()).hexdigest()
- if hashed == target_hash:
- print(f"Znaleziono hasło: {pass_d}")
- break
- else:
- print("Nie znaleziono pasującego hasła")
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: