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ę?

27 lutego 2017, 09:49 | Aktualności | komentarzy 9

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

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. .

    Polecam zainteresować się domyślnym „generatorem” UUID w Oracle DB :)
    Hint: kolejne wartości.

    Odpowiedz
    • 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 ;-)

      Odpowiedz
      • .

        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.

        Odpowiedz
      • Tag HTML Title

        Przypominam że ja istnieję! Proszęmnie używać na waszej sekurakowej stronie bo wygląda nieprofesjonalnie!

        Odpowiedz
        • Trochę mamy do nadrobienia w temacie update strony – to prawda. Jak choćby layout na smartfony. Tylko czasu brak :(

          Odpowiedz
  2. @

    To pewnie od NEWSEQUENTIALID() w T-SQL niektórym tutaj włosy siwieją ;)

    Odpowiedz
  3. 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.

    Odpowiedz
    • Zależy od wersji. Wersja 1 to w zasadzie nie jest losowa (ani pseudolosowa).

      Odpowiedz
    • hardware random number generator

      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

      Odpowiedz

Odpowiedz