NFsec Logo

Interceptor – pasywny fingerprinting botów, skanerów i innego szkodliwego oprogramowania

14/11/2021 (2 tygodnie temu) w Bezpieczeństwo Brak komentarzy.  (artykuł nr 802, ilość słów: 1735)

D

zisiaj stworzymy sobie małe wejście do szyny danych wzbogacającej o metadane adres IP klienta. Prototyp o nazwie Interceptor, który zademonstruje użyje JA3 do fingerprintingu botów, skanerów, szkodliwego oprogramowania oraz innych programów, które korzystają w komunikacji z protokołu HTTPS. Zacznijmy od JA3. Firma Salesforce otworzyła tę metodę fingerprintigu klientów TLS w 2017 roku. Podstawowa koncepcja pobierania „cyfrowych odcisków palców” od klientów TLS pochodzi z badań Lee Brotherstona (w 2015 roku wygłosił on prezentację na ten temat). Jak wiemy TLS i jego poprzednik SSL, są używane do szyfrowania komunikacji dla popularnych aplikacji, aby zapewnić bezpieczeństwo danych. Aby zainicjować sesję TLS klient wysyła pakiet: TLS Client Hello po potrójnym uścisku dłoni TCP. Pakiet ten i sposób, w jaki jest generowany, zależy od metod i innych pakietów / bibliotek oprogramowania użytych podczas budowania danej aplikacji klienckiej.

Jeśli serwer akceptuje połączenia TLS to odpowie pakietem: TLS Server Hello, który jest sformułowany na podstawie bibliotek i konfiguracji po stronie serwera, a także szczegółów w TLS Client Hello. Ponieważ negocjacje TLS są transmitowane w sposób jawny, możliwe jest przeprowadzenie fingerprintingu i zidentyfikowanie aplikacji klienckich przy użyciu szczegółów zawartych w pakiecie TLS Client Hello. Metoda JA3 służy do zbierania wartości dziesiętnych bajtów z następujących pól w pakecie TLS Client Hello:

  • Version (Wersja)
  • Accepted Ciphers (Akceptowalne szyfry)
  • List of Extensions (Lista rozszerzeń)
  • Elliptic Curves (Krzywe eliptyczne)
  • Elliptic Curve Formats (Formaty krzywych eliptycznych)

Następnie wartości te są łączone w w/w kolejności, używając znaku przecinka „,” do separacji każdego pola i znaku myślnika „-„, aby odgraniczyć każdą wartość w każdym polu. Na przykład:

769,47-53-5-10-49161-49162-49171-49172-50-56-19-4,0-10-11,23-24-25,0

W przypadku braku rozszerzeń SSL w pakiecie Hello, pola pozostają puste:

769,4-5-10-9-100-98-3-6-19-18-99,,,

Następnym krokiem jest stworzenie skrótu MD5 z tak sformatowanych ciągów tekstowych, aby stworzyć łatwy do współużytkowania 32-znakowy cyfrowy odcisk palca. To jest właśnie JA3:

769,47-53-5-10-49161-49162-49171-49172-50-56-19-4,0-10-11,23-24-25,0 
= 
ada70206e40642a3e4461f35503241d5

769,4-5-10-9-100-98-3-6-19-18-99,,, = de350869b8c85de67a350c8d186f11e6

Jeśli chcemy zobaczyć jaki skrót JA3 ma nasza przeglądarka możemy skorzystać z serwisu ja3ser, który w tym momencie posiada 128769 unikalnych haszy.

Packetbeat:

Packetbeat to lekki analizator pakietów sieciowych, który potrafi wysyłać dane z hostów i kontenerów do innych komponentów ELK Stack, takich jak Logstash lub Elasticsearch. Naszą instalację umieścimy na końcówce (serwer www / loadbalancer), gdzie terminowany jest ruch TLS z internetem. Da nam to możliwość zbierania w czasie rzeczywistym skrótów JA3 z komunikacji sieciowej klientów z naszym serwerem.

sudo apt-get install libpcap0.8
wget 'https://artifacts.elastic.co/.../packetbeat-7.15.2-amd64.deb'
wget 'https://artifacts.elastic.co/.../packetbeat-7.15.2-amd64.deb.sha512'
sha512sum packetbeat-7.15.2-amd64.deb
cat sha512sum packetbeat-7.15.2-amd64.deb.sha512
diff <(sha512sum packetbeat-7.15.2-amd64.deb | col1) \
<( cat packetbeat-7.15.2-amd64.deb.sha512 | col1)
sudo dpkg -i packetbeat-7.15.2-amd64.deb
sudo systemctl enable packetbeat

Plik konfiguracyjny: /etc/packetbeat/packetbeat.yml ogranicza się do wpisów:

packetbeat.interfaces.type: af_packet
# eth0 to interfejs publiczny
packetbeat.interfaces.device: eth0
packetbeat.interfaces.buffer_size_mb: 100

packetbeat.protocols:

- type: tls
  # łapiemy ruch https
  ports: [443]

processors:
  - drop_event:
      when:
        not:
          equals:
            # Łapiemy tylko ruch przychodzący
            network.direction: "ingress"
  - rename:
      fields:
        - from: "tls.client.ja3"
          to: "client.ja3"
      ignore_missing: true

  - include_fields:
      # Przepuszczamy dalej tylko te dwa pola
      fields: ["client.ja3", "client.ip"]

output.file:
  path: "/data"
  filename: packetbeat.log

# output.logstash:
#  hosts: ["127.0.0.1:5044"]

logging.level: info
logging.to_files: true
logging.files:
  path: /var/log/packetbeat
  name: packetbeat
  keepfiles: 7
  permissions: 0644

Po wystartowaniu serwisu packetbeat możemy przetestować skanerem nmap, co będzie przez niego łapane i w jakim formacie:

service packetbeat start
nmap --script ssl-cert -p 443 192.168.56.2
Starting Nmap 7.80 ( https://nmap.org ) at 2021-11-14 14:15 CET
Nmap scan report for darkstar (192.168.56.2)
Host is up (0.000046s latency).

PORT    STATE SERVICE
443/tcp open  https
| ssl-cert: Subject: commonName=darkstar
| Subject Alternative Name: DNS:darkstar
| Issuer: commonName=darkstar
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-10-20T19:44:07
| Not valid after:  2031-10-18T19:44:07
| MD5:   ff52 d901 ec76 da78 22f4 90c9 ccbf 4a75
|_SHA-1: fa94 e7bd d57e decc c5c2 8b8c f086 9832 1dc4 cd65

Nmap done: 1 IP address (1 host up) scanned in 0.56 seconds

root@darkstar:~# cat /data/packetbeat.log
{"@timestamp":"2021-11-14T13:15:23.998Z","@metadata":{"beat":"packetbeat","type":"_doc",
"version":"7.15.2"},"client": {"ja3":"75fe51990656df4f7a249d5b86aa29ae",
"ip":"10.0.2.15"},"type":"tls"}

Złapaliśmy właśnie JA3 skanera nmap v7.80, który użył skryptu ssl-cert. Złapmy jeszcze jeden z najczęściej używanych pakietów do obsługi ruchu HTTP(s) z poziomu języka Python:

root@darkstar:~# python3
Python 3.8.10 (default, Jun  2 2021, 10:49:15)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
<<< import requests
<<< print(requests.__version__)
2.22.0
<<< requests.get('https://192.168.56.2', verify=False)
<Response [200]>

root@darkstar:~# cat /data/packetbeat.log

{"@timestamp":"2021-11-14T13:51:52.906Z","@metadata":{"beat":"packetbeat","type":"_doc",
"version":"7.15.2"},"client":{"ja3":"a191bc14b8265666586f22ced37b9df6",
"ip":"10.0.2.15"},"type":"tls"}

Logstash:

Logstash jest narzędziem do tworzenia potoków danych, które można filtrować i przetwarzać w locie. Przyjmuje on dane z wielu źródeł, przekształca je, a następnie wysyła dalej to naszego ulubionego systemu gromadzenia i wyszukiwania danych. Połączymy go razem z packetbeat, aby stworzyć odwrotne mapowanie skrótów JA3 na konkretne identyfikatory – czyli wszystkie dane wyłapane w komunikacji TLS naszego serwera HTTP(s) przepuścimy przez naszą „bazę”, aby wyłapać interesujące nas oprogramowanie.

sudo apt-get install openjdk-11-jre-headless
wget 'https://artifacts.elastic.co/.../logstash-7.15.2-amd64.deb'
wget 'https://artifacts.elastic.co/.../logstash-7.15.2-amd64.deb.sha512'
sha512sum logstash-7.15.2-amd64.deb
cat logstash-7.15.2-amd64.deb.sha512
diff <(sha512sum logstash-7.15.2-amd64.deb | col1) \
<( cat logstash-7.15.2-amd64.deb.sha512 | col1)
sudo dpkg -i logstash-7.15.2-amd64.deb
sudo systemctl enable logstash

Plik konfiguracyjny: /etc/logstash/conf.d/logstash.conf składa się do wpisów:

# Przyjmujemy dane od packetbeat
input {
  beats {
    port => 5044
    host => "127.0.0.1"
  }
}


filter {
  # Usuwamy zbędne pola z JSON
  mutate {
    remove_field => [ "type", "@version", "tags" ]
  }
  # Szukamy i podstawiamy JA3 z naszego słownika
  translate {
    source => "[client][ja3]"
    target => "[client][id]"
    dictionary_path => "/etc/logstash/hashes.yaml"
    refresh_behaviour => "replace"
    fallback => "Unknown"
  }
}

output {
  file {
    path => "/data/logstash.log"
    codec => "json_lines"
  }
}

W celu uruchomienia naszego przechwytywacza musimy stworzyć słownik (/etc/logstash/hashes.yaml), który będzie mapować hasze JA3 na konkretne identyfikatory oprogramowania:

75fe51990656df4f7a249d5b86aa29ae: Linux - Nmap v7.80 SSL-Cert Script
a191bc14b8265666586f22ced37b9df6: Linux - Python Requests v2.22.0

W pliku konfiguracyjnym packetbeat zamieniamy wyjście danych z pliku na logstash:

# output.file:
#   path: "/data"
#   filename: packetbeat.log

output.logstash:
  hosts: ["127.0.0.1:5044"]
service packetbeat restart
service logstash start

Sprawdźmy teraz czy wykonując ponowny skan za pomocą nmap nasz system rozpozna z kim miał do czynienia:

root@darkstar:~# nmap --script ssl-cert -p 443 192.168.56.2
root@darkstar:~# cat /data/logstash.log
{"client":{"ip":"10.0.2.15","id":"Linux - Nmap v7.80 SSL-Cert Script",
"ja3":"75fe51990656df4f7a249d5b86aa29ae"},"@timestamp":"2021-11-14T15:19:06.630Z"}

Jak możemy zobaczyć rozpoznaliśmy nasz skaner. Jak duży słownik możemy stworzyć dla tego filtra? Według autorów bez problemu powinien on przyjąć 100.000 wpisów. W dodatku jego aktualizacja może odbywać się bez potrzeby restartu serwera logstash, ponieważ specjalny wątek jest odpowiedzialny za przeładowywanie jego zawartości (refresh_interval). Jedynym warunkiem jest, aby nie aktualizować go poprzez edycję w miejscu, a raczej zaktualizować go w innej lokalizacji i nadpisać jego zawartość poprzez przesunięcie pliku. To jakie dane chcemy łapać i gdzie je dalej skierujemy (w tym przykładzie zapisujemy je do pliku) zależy głównie od nas. Możemy stworzyć cyfrowe odciski złych botów, malware, skanerów itd. oraz wysłać ich adresy IP do zapory blokującej komunikację z naszymi serwerami. Możemy też nie blokować im komunikacji, a tworzyć na podstawie tych danych różne analizy i raporty, które pozwolą nam za pomocą zebranych haszy zbudować mapę ich zachowania – w jakich godzinach się pojawiają, po jakich adresach chodzą, jakie zapytania wykonują itp. Należy mieć też świadomość, że jeśli cyfrowy odcisk JA3 jest generowany przez pakiet Client Hello to możemy oczekiwać, że zobaczymy zupełnie inne aplikacje (najczęściej przeglądarki), które będą miały ten sam skrót. Jednak inaczej będzie w przypadku, gdy cyberprzestępca napisze / zbuduje własny plik wykonywalny złośliwego oprogramowania – prawdopodobnie odcisk JA3 dla niego będzie unikalny.

JA3S:

Skoro JA3 generowany jest na podstawie pakietu: Client Hello to czy można wygenerować jakiś skrót dla serwera? Tak – JA3S jest generowany na podstawie pakietu Server Hello. Tylko trick polega na tym, że serwery odpowiadają różnym klientom w różny sposób, ale zawsze będą odpowiadać temu samemu klientowi w ten sam sposób. Wyżej wspomniałem, że własnoręcznie napisane oprogramowanie powinno mieć raczej unikalny skrót JA3. Ale, co jeśli napisana przez nas aplikacja używa wspólnych bibliotek lub gniazd systemu operacyjnego do komunikacji? JA3 w tym wypadku może być powtarzalny. I tutaj JA3S może pomóc w identyfikacji złośliwej komunikacji.

Na przykład: zarówno Meterpreter Metasploita, jak i Beacon Cobalt Strike używają gniazda Windows do inicjowania komunikacji TLS. Dla Windows 10 jest to 72a589da586844d7f0818ce684948eea (łączenie się klienta z adresem IP serwera) a0e9f5d64349fb13191bc781f81f42e1 (łączenie się klienta z domeną serwera). Inne legalne aplikacje (np. Excel, Teams) w systemie również używają tych gniazd sieciowych, co utrudnia identyfikację. Jednak sposób, w jaki serwery C2 postawione na systemie Kali Linux odpowiadają na łączność z tych aplikacji klienckich, jest wyjątkowy w porównaniu ze sposobem, w jaki odpowiadają normalne serwery w internecie. Jeśli więc połączymy JA3 + JA3S będziemy w stanie zidentyfikować taką złośliwą komunikację niezależnie od adresu, domeny i certyfikatu serwera. Przykład wyszukiwania:

# Metasploit - Windows 10 (klient) Kali Linux (serwer)
(JA3=72a589da586844d7f0818ce684948eea OR JA3=a0e9f5d64349fb13191bc781f81f42e1)
AND JA3S=70999de61602be74d4b25185843bd18e

# Cobalt Strike - Windows 10 (klient) Kali Linux (serwer)
(JA3=72a589da586844d7f0818ce684948eea OR JA3=a0e9f5d64349fb13191bc781f81f42e1) 
AND JA3S=b742b407517bac9536a77a7b0fee28e9 

Jak zostało to powiedziane wcześniej: skróty komunikacji TLS, niezależnie czy to od strony klienta, czy to serwera mogą powodować fałszywe alarmy. Możemy myśleć o JA3 jako odpowiedniku User-Agent w TLS. Tylko dlatego, że jedno legalne lub złośliwe oprogramowanie ma określony skrót, nie oznacza, że zawsze będzie ono unikalne dla tego oprogramowania, ponieważ inne korzystające z tego samego stosu sieciowego może przedstawiać się identycznie. Nie ma jednak powodu, aby nie używać tego ciągu do rozszerzania analizy i wykrywania nadużyć. Jest to kolejna metadana sieciowa, którą możemy wykorzystać do wzbogacania danych. Śledzenie komunikacji JA3S w połączeniu z JA3 może znacznie zmniejszyć poziom alarmów false positive, jeśli szukamy konkretnej komunikacji.

Więcej informacji: TLS Fingerprinting with JA3 and JA3S, Profiling And Detecting All Things SSL With JA3 – John Althouse and Jeff Atkinson, Inspecting encrypted traffic with JA3 and JA3S fingerprinting, Hiding behind JA3 hash, Passive OS fingerprinting

Kategorie K a t e g o r i e : Bezpieczeństwo

Tagi T a g i : , , , , , , , ,

Komentowanie tego wpisu jest zablokowane.