Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Jak przewidzieć UUID/GUID, który będzie wygenerowany za chwilę?
Co powiecie o takim UUID: 01f3cf39-fb6e-11e6-874a-4c72b97ca1e7 ? Czy jest on w pełni losowy, a może udałoby się coś powiedzieć do dacie jego stworzenia? A może wyciągnąć nawet więcej?
Tego typu ciągi stosowane są najczęściej do identyfikowania rozmaitych obiektów (rekordów w bazie, dokumentów, użytkowników w Windows, etc). Istnieje przekonanie, że UUID są losowe (stąd trudno odgadnąć ID np. dokumentu innego użytkownika).
Zobaczmy jak wygląda struktura przykładowego UUID:
mysql> select uuid(); +--------------------------------------+ | uuid() | +--------------------------------------+ | 01f3cf39-fb6e-11e6-874a-4c72b97ca1e7 | +--------------------------------------+
W opisie UUID czytamy, że możliwych jest aż pięć wersji tego ciągu (przy czym długość oraz alfabet, z którego jest generowany ciąg są takie same, różna jest wewnętrzna struktura).
Jak przeanalizować powyższy UUID? Np. w Pythonie:
>>> import uuid >>> moj_uuid = uuid.UUID('{01f3cf39-fb6e-11e6-874a-4c72b97ca1e7}') >>> moj_uuid.version 1 >>>
Wersja pierwsza nie ma żadnej losowości, a bazuje tylko na trzech czynnikach:
- Data stworzenia (podawana nieco egzotycznie: number of 100-nanosecond intervals since midnight 15 October 1582)
- Adres MAC komputera (czy dokładniej: jego karty sieciowej), na którym powstał UUID
- Niewielka (14 bitowa) wartość clock sequence
Dla porównania UUID w wersji czwartej:
>>> uuid.uuid4() UUID('be975b97-bbad-4e4f-a143-4daaf8020194')
Wygląda podobnie jak ten z MySQL, prawda? Wróćmy do naszego przykładu i spróbujmy wydobyć datę stworzenia z pierwszego UUID:
>>> import datetime >>> datetime.datetime.fromtimestamp((moj_uuid.time - 0x01b21dd213814000L)*100/1e9) datetime.datetime(2017, 2, 25, 16, 20, 57, 910866) >>>
Wygląda jak świeża data, prawda? :) Zobaczmy teraz adres MAC. Tutaj jest trochę zabawy z kodowaniem (normalnie dostajemy wartość jako liczba całkowita):
>>> import re >>> mac = hex(moj_uuid.node) >>> mac = mac[2:][:-1] >>> mac '4c72b97ca1e7' >>> mac_normal = ':'.join(re.findall('..', mac)) >>> mac_normal '4c:72:b9:7c:a1:e7'
Co idealnie zgadza się z adresem fizycznym karty sieciowej komputera, na którym został wygenerowany UUID.
Na koniec clock sequence:
>>> moj_uuid.get_clock_seq() 1866L
Wnioski
Jeśli mamy ciąg w formacie UUID w wersji 1, możemy określić adres MAC maszyny gdzie został on wygenerowany. Następnie możemy próbować generować inne UUIDy, które zostały stworzone w danym czasie (!) – np. dzień temu. Do układanki zostaje tylko bruteforce clock sequence (16384 możliwych wartości) + odpowiednie wpasowanie się z czasem…
Sposób tworzenia UUID może być też czasem użyty do namierzenia danej osoby – np. autora dokumentu .doc. Tak się kiedyś stało z autorem robaka Melissa:
Using the controversial GUID that records the MAC address into Word documents, researchers discovered that the MAC address in the Melissa virus matches the address in other macros viruses from a virus author who goes by the handle Vicodin ES.
Obecnie Microsoft (ponoć :) używa UUID (bardziej precyzyjnie GUID-a) w wersji czwartej (większość jego zawartości jest losowa). Choć jak widać wyżej – MySQL używa domyślnie wersji 1.
Możemy się więc tego niebezpiecznego wariantu spodziewać w świecie rzeczywistym, a dostępny jest nawet plugin do Burp Suite, który automatycznie analizuje problem (sam plugin zresztą był inspiracją do napisania tego krótkiego tekstu).
–Michał Sajdak
Polecam zainteresować się domyślnym „generatorem” UUID w Oracle DB :)
Hint: kolejne wartości.
Ogólnie podejrzewam że na rynku panuje a) względna wolna amerykanka jak różne systemy generują UUID b) niemal wszyscy myślą że to zawsze są losowe wartości ;-)
I niestety ludzie tego nie sprawdzają, więc korzystają z takich sekwencyjnych, myśląc że są losowe.
W Oracle DB poza XE można dodać kod w Javie do generowania UUID o jakiejś losowości, co oczywiście jest paskudnym rozwiązaniem, ale przynajmniej daje wynik trochę wyższej jakości.
Ciekawie się to rozwiązuje w kilkuletniej bazie aplikacji z około 100 tysiącami użytkowników – pomapuj sobie teraz stare uuidy na nowe.
Przypominam że ja istnieję! Proszęmnie używać na waszej sekurakowej stronie bo wygląda nieprofesjonalnie!
Trochę mamy do nadrobienia w temacie update strony – to prawda. Jak choćby layout na smartfony. Tylko czasu brak :(
To pewnie od NEWSEQUENTIALID() w T-SQL niektórym tutaj włosy siwieją ;)
Ok… UUID jest wartością PSEUDO losową, zatem znając algorytm i ziarno użyte do wyliczania możemy określić kolejne wartości.
To, że algorytm UUID w tym przypadku nie wprowadza, żadnego elementu trudnego do przewidzenia np. poprzedniej wartości UUID tylko ułatwia zadanie.
Zależy od wersji. Wersja 1 to w zasadzie nie jest losowa (ani pseudolosowa).
UUID w wersji 4 nie precyzuje jakiej konkretnie techniki użyjesz do wylosowania bitów. W związku z tym nie można powiedzieć, że „UUID jest wartością PSEUDO losową”, może lecz nie musi