Odciski palca zostawiane przez protokół TLS (TLS fingerprinting)

Wstęp

Protokół TLS (Transport Layer Security) został zaprojektowany w celu zapewnienia prywatności i bezpieczeństwa danych w komunikacji internetowej. Stworzony został na bazie starszego protokołu SSL (Secure Sockets Layer), dlatego obie nazwy bywają czasem stosowane zamiennie. Pierwszą wersję TLS opublikowano w 1999 roku, natomiast jego najnowszą wersję — TLS 1.3 — w roku 2018.

TLS najczęściej wykorzystywany jest w szyfrowaniu aplikacji webowych. Oparty jest na nim m.in. protokół HTTPS, domyślnie wykorzystywany przez ponad 83% wszystkich stron internetowych.

Z definicji komunikacja zabezpieczana protokołem TLS powinna być (podatności w różnych wersjach protokołu SSL/TLS to temat na oddzielny artykuł) bezpieczna, to znaczy, że protokół zapewnia:

  • Szyfrowanie danych
  • Uwierzytelnianie stron komunikacji
  • Integralność przesyłanych danych

Więc jakim “odciskom palca” poświęcony jest ten artykuł?

Pełne zrozumienie TLS fingerprintingu wymaga najpierw określonych elementów protokołu TLS (pełne omówienie protokołu TLS spowodowałoby znaczne wydłużenie tego artykułu, a na potrzeby tematu nie ma sensu omawiać każdego detalu, ale spokojnie, wrócimy do tego przy omawianiu podatności SSL/TLS). Ludzi znających arkany funkcjonowania tego protokołu oraz pozostałych niecierpliwych zapraszam tutaj.

Omówienie wybranych elementów protokołu TLS (w wersji 1.3)

TCP handshake

Protokół TLS oparty jest na protokole TCP, dlatego każda komunikacja wymaga najpierw charakterystycznego dla TCP 3-way handshake. To w ramach krótkiej informacji dla tych, których mogłoby to zaskoczyć podczas analizy ruchu sieciowego.

TLS handshake

Komunikacja wykorzystująca protokół TLS rozpoczyna się od tzw. TLS handshake. Hosty weryfikują swoją tożsamość, wymieniają między sobą klucze kryptograficzne (znowu, szczegóły tego procesu niepotrzebnie wydłużyłyby artykuł, przyjdzie czas na omówienie również i tego zagadnienia) oraz negocjują między sobą parametry protokołu wykorzystywane w dalszej części komunikacji. Składają się na niego trzy fazy:

  1. Faza negocjacji:

    • Klient wysyła wiadomość ClientHello, w której warte uwagi są następujące pola:

      • Version — pole określające wersję protokołu TLS gdzie dochodzi do czegoś na pierwszy rzut oka nielogicznego — w nagłówku ewidentnie widnieje wersja TLS 1.2, ale o to właśnie chodzi! Do gry wchodzi tutaj kochana kompatybilność wsteczna... Jeśli serwer nie obsługuje TLS 1.3 (co niestety ciągle jest powszechne, pięć lat po wydaniu tej wersji protokołu…) dalsza komunikacja odbywa się z wykorzystaniem protokołu w wersji 1.2 (co nie jest tutaj omawiane). Pozostaje pytanie skąd w takim razie serwer ma się dowiedzieć, że klient najbardziej chce komunikować się z wykorzystaniem protokołu 1.3? Wszystko w swoim czasie.

      • Cipher Suites — pole zawiera listę szyfrów symetrycznych wspieranych przez klienta, które mogą być wykorzystane w dalszej komunikacji

        Przykładowe Cipher Suites

      • Extensions — pola rozszerzeń są miejscem, w którym zaczyna się prawdziwy ból głowy, bo ich może być naprawdę sporo. Oferują one dodatkowe funkcjonalności przy jednoczesnym zapewnieniu jak największego stopnia kompatybilności wstecznej. Wartymi uwagi rozszerzeniami są:

        • supported_groups — rozszerzenie używane do negocjowania parametrów wykorzystywanych podczas szyfrowania za pomocą krzywych eliptycznych (zalecany rodzaj szyfrowania w protokole TLS i najczęściej wykorzystywany, dlatego to rozszerzenie, wraz z ec_point_formats można zauważyć w zdecydowanej większości ruchu TLS)

          Przykład rozszerzenia supported_gropus

        • ec_point_formats — rozszerzenie wskazujące jakie formaty punktów kryptografii krzywych eliptycznych potrafi obsłużyć klient

          Przykładowe ec_point_formats

        • supported_versions — tutaj mamy odpowiedź na pytanie, skąd serwer ma wiedzieć, że klient chce używać protokołu TLS w wersji 1.3. Rozszerzenie to zawiera listę obsługiwanych przez klienta wersji protokołu TLS

          Przykładowe supported_versions

      Przykładowy pakiet ClientHello widziany w Wiresharku:

      Przykładowy pakiet ClientHello widziany w Wiresharku

    • Serwer odpowiada wiadomością ServerHello, w której wskazuje wybraną przez niego wersję TLS (mamy tutaj dokładnie ten sam fikołek zrobiony w celu zachowania kompatybilności wstecznej — pole Version wskazuje na TLS 1.2, ale w rozszerzeniach wskazana jest już prawidłowa wersja 1.3) oraz algorytm szyfrujący. Zawiera również dodatkowe rozszerzenia. Przykładowy pakiet ServerHello widziany w Wiresharku:

      Przykładowy pakiet ServerHello widziany w Wiresharku

  2. Serwer wysyła rekord ChangeCipherSpec, z założenia ma on informować, że od tego momentu każdy ruch pochodzący z serwera jest szyfrowany. Ma on jednak znaczenie tylko dla kompatybilności wstecznej, stąd też widnieje w nim wersja TLS 1.2. Przykładowy rekord ChangeCipherSpec widziany w Wiresharku:

    Przykładowy rekord ChangeCipherSpec

  3. Klient wysyła ChangeCipherSpec, identyczny jak ten wysyłany przez serwer.

TLS fingerprinting

Z powyższego pobieżnego opisu widać jedną rzecz — protokół TLS potrafi być bardzo złożony, poprzez wspieranie wielu różnych opcji, algorytmów szyfrowania etc. przez co istnieje bardzo wiele możliwych kombinacji stosowanych parametrów. Na ich podstawie można skutecznie identyfikować hosty w sieci. Może nie jest to aż tak dokładne jak biologiczny odcisk palca, jednak ciągle jest to bardzo przydatne narzędzie w threat huntingu (gdzie TLS fingerprinting może być z powodzeniem wykorzystywany jako Indicator of Compromise — IoC), filtrowaniu ruchu sieciowego i nie tylko. Jednymi z najpopularniejszych metod TLS fingerprintingu są otwartoźródłowe JA3, JA3S oraz JARM opracowane przez firmę Salesforce.

JA3

JA3 analizuje pakiet ClientHello w poszukiwaniu następujących pól: TLSVersion, Ciphers, Extensions, EllipticCurves, EllipticCurvePointFormats Przykładowa wiadomość ClientHello z zaznaczonymi polami, na podstawie których powstaje JA3 fingerprint:

ClientHello z zaznaczonymi polami

Wartości tych pól są pobierane w formacie dziesiętnym, a następnie łączone. Przecinek oddziela poszczególne pola, natomiast myślnik oddziela wiele wartości wchodzących w skład danego pola, na przykład: 771,49195-49199-49196-49200-52393-52392-49161-49171-49162-49172-156-157-47-53-49170-10-4865-4866-4867,0-5-10-11-13-65281-16-18-43-51,29-23-24-25,0

Jeśli ClientHello nie zawiera żadnych rozszerzeń TLS, pole jest pozostawiane puste, na przykład: 769,4–5–10–9–6–19–18–99,,,

Jak widać, wynik potrafi być naprawdę długi, dlatego dodatkowo hashuje się go algorytmem MD5: 771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-156-157-47-53,0-23-65281-10-11-16-5-34-51-43-13-45-28-41,29-23-24-25-256-257,0 -> c279b0189edb9269da7bc43dea5e0c36

JA3 stanowi skuteczne narzędzie do wykrywania malware w ruchu sieciowym. Przykładowe JA3 Cobalt Strike: 72a589da586844d7f0818ce684948eea

JA3S

JA3S działa analogicznie względem JA3, jednak poddaje on analizie pakiet ServerHello. Składnia i zasada działania analogiczna jak w jego klientowym odpowiedniku, różnica tkwi tylko w wykorzystywanych polach: TLSVersion, Cipher, Extensions Przykładowa wiadomość ServerHello z zaznaczonymi polami, na podstawie których powstaje JA3S fingerprint:

ClientHello z zaznaczonymi polami

Zebrane dane są na ogół krótsze od JA3, jednak je również poddaje się hashowaniu algorytmem MD5: 771,4865,41-51-43 -> 2b0648ab686ee45e0e7c35fcfb0eea7e

JA3S podobnie jak JA3 stanowi przydatne narzędzie służące do określania IoC. Przykładowe JA3S Cobalt Strike: b742b407517bac9536a77a7b0fee28e9

JARM

JA3 oraz JA3S działają w sposób pasywny — jedynie analizują podsłuchane pakiety ruchu sieciowego. Odmienne działanie ma JARM, który stanowi przykład aktywnego fingerprintingu. Opiera się na tym, że serwer konstruuje pakiet ServerHello na podstawie informacji otrzymanych w wiadomości ClientHello. Sposób, w jaki ten pakiet jest tworzony, różni się również w zależności od czynników powiązanych z samym serwerem, takich jak np. system operacyjny, wykorzystywane biblioteki i ich wersje etc. JARM działa poprzez aktywne wysłanie dziesięciu różnych pakietów ClientHello do docelowego serwera TLS. Pakiety te zostały specjalnie dobrane przez twórców w celu wydobycia unikalnych odpowiedzi od serwerów TLS, różnią się one m.in. wersjami protokołu, proponowanymi szyframi i rozszerzeniami. JARM fingerprint jest hybrydowym 62-znakowym hashem stanowiącym połączenie odwracalnych i nieodwracalnych hashy. Pierwsze 30 znaków jest tworzonych na podstawie wybranego algorytmu szyfrującego i wersji TLS dla każdego z wysłanych ClientHello. Każdy wysłany rekord jest reprezentowany przez ciąg trzech znaków. Ciąg 000 oznacza wtedy, że serwer odmówił dalszej komunikacji z klientem. Pozostałe 32 znaki to ucięty hash SHA256 połączonych rozszerzeń wysyłanych przez serwer, z pominięciem danych certyfikatów x509. Przykładowo dla fingerprinta 27d27d27d29d27d1dc41d43d00041d741011a7be03d7498e0df05581db08a9

Pierwsze 30 znakówPozostałe 32 znaki
27d27d27d29d27d1dc41d43d00041d741011a7be03d7498e0df05581db08a9
Wybrane algorytmy i wersje TLSUcięty hash SHA256 rozszerzeń

Jeśli przy porównywaniu hashy natrafimy na sytuację kiedy pierwsze 30 znaków jest taka sama, to może oznaczać, że serwery mają bardzo podobną konfigurację w zakresie akceptowania różnych wersji TLS i wyboru algorytmu szyfrującego. Przykładem jest porównanie trzech różnych serwerów tej samej korporacji:

DomenaJARM fingerprint
google.com27d40d40d29d40d1dc42d43d00041d4689ee210389f4f6b4b5b1b93f92252d
youtube.com27d40d40d29d40d1dc42d43d00041d4689ee210389f4f6b4b5b1b93f92252d
gmail.com27d40d40d29d40d1dc42d43d00041d4689ee210389f4f6b4b5b1b93f92252d

JARM może być skutecznym narzędziem przy wykrywaniu serwerów C2. Przykładowy JARM fingerprint Cobalt Strike: 07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1

Podsumowanie

Jak widać, protokół TLS oferuje w swojej specyfikacji bardzo wiele możliwości, których umiejętne wykorzystanie daje potężne narzędzie w ręce osób związanych z cyberbezpieczeństwem bądź sieciami komputerowymi. Ważna jest wiedza jak umiejętnie je wykorzystywać, ale i pożądane jest dzielenie się swoimi odkryciami np. nowymi fingerprintami malware, aby inni mogli z nich korzystać.