Jak działają carderzy: analiza techniczna Antidetecta

dodał 20 listopada 2019 o 07:26 w kategorii HowTo, Info  z tagami:
Jak działają carderzy: analiza techniczna Antidetecta

Dzisiaj zapraszamy na trzeci już odcinek z podróży po świecie carderów. Tym razem przyjrzymy się dokładnie jednemu z ich ulubionych narzędzi, tzw. Antidetectowi. Przewodnikiem po tym ciekawym świecie będzie Marcin Mostek.

Skoro mamy już przedstawioną panoramę najpopularniejszych rozwiązań używanych do oszukiwania systemów antyfraudowych wraz z możliwościami, jakie oferują, należałoby lepiej przeanalizować sposób, w jaki działają one „pod maską”. Jako że autor posiada skończone zasoby wolnego czasu i chęci, w poniższej części artykułu skupimy się na najdłużej istniejącym rozwiązaniu o nazwie Antidetect, a konkretnie na wersji 7.3.

W analizowanej wersji Antidetect zawiera następujące pliki / foldery:

  • Antidetect Browser
    Plik wykonywalny będący unpackerem całego programu.
  • antidetect.cc
    Plik binarny zawierający zaszyfrowane zmodyfikowane wersje Firefoksa portable, będącego podstawą działania całego narzędzia.
  • folder fla
    Folder zawierający spatchowane wersje wtyczki Flash przeznaczone do Firefoksa, umożliwiające modyfikacje danych zwracanych przez API wtyczki. Wtyczki są skonfigurowane w ten sposób, by nie aktywował się mechanizm auto-update.
  • folder configs
    Folder zawierający wiele profili ustawień służących do spoofowania przeglądarek z różnych systemów operacyjnych i urządzeń. Folder może zawierać następujące pliki:
    • config.ini wypełniony tylko w wypadku, w którym dany profil powinien mieć możliwość uruchomienia wtyczki Flash (czyli najczęściej Windows); zawiera informacje o czcionkach jakie mają zostać zwrócone poprzez API Flasha,
    • jsoverider.js zawierający zwykle kod mający na celu oszukać canvas fingerprint (zwykle ten plik nie jest wykorzystywany),
    • jsoverider.json – plik konfiguracyjny zawierający wszystkie ustawienia, jakie mają zostać podmienione podczas spoofingu przeglądarki i urządzenia (DOM API),
    • modifyheaders.conf – plik zawierający instrukcje mające na celu poinformowanie przeglądarki, w jaki sposób ma spoofować nagłówki HTTP,
    • useragent.txt – plik zawierający informacje o urządzeniu, na podstawie którego powstał profil przeglądarki (system operacyjny, przeglądarka, rozdzielczość ekranu, język, obecność wtyczki Flash),
    • usercontent.css – plik zawierający informacje, jakie czcionki mają zostać spoofowane.
  • plik overrider.xpi
    Rozszerzenie do Firefoksa faktycznie realizujące część funkcji narzędzia.
Przykładowa zawartość pliku jsoverrider

Uruchomienie pliku Antidetect browser powoduje skopiowanie folderów zawierających pliki konfiguracyjne oraz zmodyfikowane wersje wtyczki Flash do folderu tymczasowego (%AppData%/local/Temp). Wraz z tymi plikami kopiowany jest wcześniej wymieniony dodatek overrrider.xpi . W tej samej lokacji wypakowywany jest również właściwy plik wykonywalny narzędzia, który jest następnie uruchamiany.

Po uruchomieniu pliku oczom użytkownika ukazuje się ekran rejestracyjny wraz z wygenerowanym identyfikatorem sprzętowym. Identyfikator ten służy do wygenerowania przez twórcę oprogramowania klucza umożliwiającego odblokowanie pełnej wersji narzędzia. Istnieje też możliwość uruchomienia ograniczonej czasowo wersji testowej.

Ekran rejestracji

Po przejściu rejestracji należy wybrać miejsce, w którym przechowywany jest plik binarny antidetect.cc, który zostanie rozpakowany do pamięci i uruchomi właściwe okno programu. Plik ten jest zabezpieczony hasłem.

Otwieranie zabezpieczonego hasłem pliku binarnego antidetect.cc

Po wybraniu przez użytkownika odpowiednich opcji konfiguracyjnych (wersji Firefoksa i Flasha oraz urządzenia wraz z przeglądarką, która ma zostać zespoofowana) następuje wypakowanie na dysk przeglądarki w wersji portable (ponownie %AppData%/local/Temp). Wypakowana przeglądarka jest oczywiście odpowiednio zmodyfikowana:

  • wyłączone są automatyczne aktualizacje przeglądarki,
  • wyłączona jest usługa healthreport odpowiedzialna za przesyłanie informacji na temat wydajności i stabilności przeglądarki,
  • wyłączone są API związane ze statusem baterii czy webworkerami,
  • wyłączone są pluginy,
  • wyłączona jest usługa odpowiedzialna za synchronizowanie ustawień pomiędzy komputerami,
  • wyłączone jest przesyłanie raportów dotyczących crashy,
  • rejestrowany jest wcześniej wspomniane rozszerzenie overrider.xpi (umieszczane jest ono w folderze /data/profile/extensions w miejscu, gdzie wypakowana została przeglądarka),
  • w folderze /App/Firefox/browser zostają umieszczone dwa dodatkowe pliki – jsoverider.js i jsoverider.json,
  • w folderze /Data/profile/chrome pojawia się plik userContent.css,
  • w folderze /Data/plugins pojawia się spatchowana wtyczka Flash (tylko w przypadku odpowiedniego systemu).

Po uruchomieniu przeglądarki wgrywane jest rozszerzenie wytworzone przez twórców Antidetecta, które realizuje przeważającą część funkcji programu.

Instalacja rozszerzenia w nowo rozpakowanej wersji portable Firefoksa

Plik jsoverrider.js jest generowany na podstawie wcześniej wybranych opcji (np. czy został włączony spoofing webRTC) i może zawierać następujący kod:

TL;DR dla leniwych: Funkcja hookuje API odpowiedzialne za canvas i WebGL fingerprinting zwraca podstawione wartości. Dodatkowo spoofowane są wartości odpowiedzi z API WebRTC, z których wydobywa się zwykle adresy IP. Przy każdym ponownym uruchumieniu przeglądarki za pomocą Antidetecta (nawet w dokładnie tej samej konfiguracji) wypakowywana jest zupełnie nowa instancja przeglądarki i losowane są nowe wartości mające zrandomizować fingerprint czy zmienić odpowiedź z WebRTC. Podejście tego typu zapewnia również czyszczenie wszelkiego rodzaju cookies.

Plik jsoverider.json zawiera zestaw dyrektyw dla rozszerzenia Antidetect dotyczących tego, jakie informacje mają zostać podmienione i jaką mają zawierać treść. Przykładowo mogą to być:

  • API powiązane z rozdzielczością,
  • informacje o User-Agencie i przeglądarce,
  • informacje o zainstalowanych pluginach,
  • informacje o obsługiwanych typach plików (mimeTypes).

Wszystkie wartości w tym pliku pochodzą z wybranego wcześniej przez użytkownika profilu spoofowania przeglądarki. Profile te mają pochodzić od realnych urządzeń. Co ciekawe, w pliku tym można znaleźć takie fragmenty kodu:

Służą one ukryciu faktu podmienienia funkcji. W przypadku gdy dana funkcja zapewniana przez przeglądarkę zostanie podmieniona, np. tak jak to miało miejsce w przypadku window.mozRTCPeerConnection z pliku jsoverrider.js, to wywołanie na niej metody toString() zwróci ciało funkcji zamiast [native code].

Przykładowo:

zwróci:

zaś po nadpisaniu funkcji za pomocą:

wywołanie:

zwróci:

Rozszerzenie umożliwia przejście na najpopularniejsze serwisy weryfikujące skuteczność fingerprintingu

Kolejnym plikiem wartym przeanalizowania jest userContent.css. Według wiki Mozilli plik ten nie pojawia się domyślnie przy tworzeniu nowego profilu przeglądarki i musi zostać dodany manualnie. Służy on do personalizacji wyglądu stron WWW (w przypadku Firefoksa) lub templatów mailowych (w przypadku Thunderbirda). Powyższe zmiany widoczne są tylko lokalnie. Można zadać sobie pytanie – po co twórcy Antidetecta włożyli dodatkową pracę w tworzenie pliku modyfikującego wygląd stron? Czy są aż takimi estetami? Okazuje się, że nie, przynajmniej nie w tym wypadku – plik ten jest wykorzystywany do spoofowania czcionek. Jak to? – spyta zaintrygowany czytelnik. Bardzo prosto:

Powyższą regułę CSS w uproszczeniu należy rozmieć w następujący sposób:
w przypadku żądania użycia czcionki o nazwie „AlNile” wykorzystaj lokalną czcionkę o nazwie „Arial”. Jako że czcionka „Arial” występuje w praktycznie każdym systemie, „AlNile” zostanie na pewno wyrenderowany. Metoda ta jest w stanie z powodzeniem oszukać algorytm fingerpintowania czcionek opisany w poprzedniej części artykułu. Plik userContent.css zawiera naturalnie więcej niż jedną taką dyrektywę i generowany jest na podstawie wybranego przez użytkownika profilu spoofowanej przeglądarki analogicznie jak jsoverrider.json (patrz też opis folderu configs).

Jednak najważniejszą częścią całego programu jest niezaprzeczalnie rozszerzenie Firefoksa – to ono spaja wszystkie opisywane wcześniej części, a także realizuje dodatkowe funkcje. By lepiej zrozumieć działanie narzędzia, należy wpierw zrozumieć przynajmniej pobieżnie architekturę i możliwości rozszerzeń tworzonych do Firefoksa. Tworząc przykładowe rozszerzenie, można:

  • modyfikować wygląd i działanie wszystkich stron WWW, np. poprzez wstrzykiwanie dodatkowego kodu JS, usuwanie elementów ze strony czy modyfikowanie już istniejących,
  • modyfikować działanie samej przeglądarki, np. poprzez dodawanie nowych funkcji, części interfejsu lub modyfikowanie API JS,
  • przechwytywanie zapytań HTTP i HTTPS oraz ich modyfikacji.

Twórcy przeglądarek nie chcieli zbytnio komplikować procesu tworzenia takich rozszerzeń, toteż wykorzystali oni w tym celu dobrze znane technologie HTML i CSS do tworzenia interfejsu użytkownika i JavaScript do logiki biznesowej. Poza standardowymi API znanymi z klasycznego JavaScriptu dodano też dodatkowe API umożliwiające dużo większe możliwości interakcji z przeglądarką i odwiedzanymi stronami.  Rozszerzenia mogą również cieszyć się innymi (bardziej liberalnymi) zasadami  przesyłania informacji między domenami.

Z racji wykorzystywania przez Antidetect starszych wersji Firefoksa do napisania rozszerzenia zostały użyte API oznaczone już jako porzucone (bootstraped extensions). W zamierzchłych czasach, których nie pamiętają już najstarsi górale, rozszerzenia Firefoksa oparte były o tak zwane overlays i windows. Rozszerzenia tego typu pozwalały na wczytanie z plików XUL (XML User Interface Language) informacji na temat interfejsu i  stworzenie tytułowego overlay, które rozszerzało window o dodatkowe elementy. Przykładowo window reprezentujące przeglądarkowy interfejs pobierania plików było rozszerzane przez overlay dodający do niego dodatkowe przyciski definiowane przez rozszerzenie. Rozwiązanie to miało jednak jedną wadę – przy operacjach takich jak instalacje nowych rozszerzeń czy wyłączanie starych należało restartować przeglądarkę. Postanowiono temu zaradzić poprzez wprowadzenie bootstraped extensions. Główną zaletą tego typu rozszerzeń było wymaganie od nich rozpoczęcia / zatrzymania działania w dowolnym momencie działania przeglądarki. Odbywało się to przez zdefiniowane funkcje startup() i shutdown(). Podczas wywołania startup() musiała ona ręcznie wstrzyknąć tworzony przez rozszerzenie interfejs użytkownika wraz z jego logiką do przeglądarki, podczas gdy funkcja shutdown() musiała „posprzątać” wstrzyknięte informacje.

Kolejnym ważnym założeniem architektonicznym w przypadku rozszerzeń Firefoksa jest podział na Content Script i Add-on Script.

Add-on Script, jak sama nazwa wskazuje, jest kodem związanym z logiką rozszerzenia (zwykle plik main.js i zawartość folderu lib). Ma on dostęp do całego API SDK przewidzianego dla rozszerzeń, aczkolwiek nie ma bezpośredniej możliwości modyfikowania stron w przeglądarce. Content Script natomiast może bezpośrednio modyfikować strony, ale nie może odwoływać się do API SDK. Zwykle do Content Script zaliczają się wszelkie pliki znajdujące się w folderze data. Umieszcza się tam pliki powiązane z interfejsem rozszerzenia (jest on definiowany za pomocą HTML, JS i CSS). Należy pamiętać, że interfejs dodawany przez rozszerzenie jest wyświetlany jako normalna strona WWW wraz z własnym obiektem window. Nie jest ona jednak widoczna z poziomu użytkownika.

Ciekawostka mostka

Naturalnie autor częściowo (jak zwykle) mija się z prawdą.  Jakiś czas temu był możliwy atak za pomocą pseudoprotokołu chrome:// umożliwiającego enumeracje zasobów Content Script i tym samy określenie jakie rozszerzenia dany użytkownik ma zainstalowane. Dokładniejszy opis można przeczytać tu. Blog ten jest bardzo dobrym źródłem uciech, które są fundowane researcherom przez twórców przeglądarek i rozszerzeń do nich.

Bardzo często zachodzi potrzeba przekazywania informacji pomiędzy tymi dwiema warstwami, np. gdy główny skrypt dokonał jakiejś zmiany za pomocą SDK API i należy ją wyświetlić użytkownikowi. Do takowej komunikacji mógł być używany obiekt port. Metoda port.emit() pozwalała na wysłanie informacji, zaś metoda port.on() na jej odebranie i reakcję na nią.

Komunikacja pomiędzy Content Script i Add-on Script

Struktura rozszerzenia wygląda następująco:

  • folder data
    zawierający  wszelkie elementy dotyczące interfejsu rozszerzenia – pliki css, html, czcionki, biblioteki pomocnicze (bootstrap, jquery), a także JavaScript odpowiedzialny za logikę działania GUI.
  • folder lib
    zawierający wszelką logikę biznesową:
    • plik /files/FileIO.js
      odpowiedzialny za operacje na plikach (wczytywanie, zapisywanie itp.),
    • plik /files/InjectScriptHandler.js
      służący do wczytywania pliku jsoverrider.js zawierającego kod, który ma zostać wstrzyknięty w przeglądarkę, zwykle są to funkcje służące do spoofowania WebRTC, WebGL czy canvas fingerprintu,
    • plik /files/NavigatorConfigHandler.js
      służący do wczytania pliku jsoverrider.json zawierającego wytyczne, jak spoofować poszczególne API przeglądarkowe, np. dotyczące rozdzielczości. Dodatkowo parsuje dane takie jak User-Agent, języki czy oscpu w celu wyświetlenia ich w GUI rozszerzenia,
    • plik HTTPRequestOverrider.js
      serce całego narzędzia, wbrew nazwie nie zajmuje się tylko nadpisywaniem właściwości żądań HTTP, ale też wstrzykiwaniem skryptów czy podmianą danych zwracanych przez API przeglądarki,
    • plik IPAdressMonitor.js
      służący do cyklicznego sprawdzania zewnętrznego adresu IP poprzez odpytania na adres „https://api.ipfy.org”. W przypadku gdy nastąpi jakakolwiek zmiana adresu IP, użytkownik jest o niej natychmiast powiadamiany.
  • plik bootstrap.js
    Wymagany przez wcześniej opisany mechanizm bootraped extension.
  • plik install.rdf
    Manifest instalacji rozszerzenia zawierający metadane o dodatku.
  • plik main.js
    Entry point rozszerzenia Antidetect, zawiera wywołania całej logiki.
  • plik package.json
    Zawiera metadane dotyczące rozszerzenia, np. jakie wersje są obsługiwane, kto jest autorem (w tym wypadku „honest_and_sweet_guy” :) ) i jaki jest główny entry point pluginu (main.js).

Po tym wstępnym zapoznaniu można przyjrzeć się plikowi main.js. Na samym początku skrypt tworzy „obiekty” mające odczytać wcześniej opisane pliki jsoverrider.json i jsoverrider.js:

Następnie definiowana jest funkcja mająca na celu wyświetlenie informacji o zawartości poszczególnych plików w interfejsie graficznym rozszerzenia:

Możliwość zmiany spoofowanych wartości w locie oferowana przez rozszerzenie

Jako że API jest asynchroniczne, do obsługi wczytania plików konfiguracyjnych używana jest promisa (więcej na temat tego mechanizmu można przeczytać pod tym adresem). W przypadku pomyślnego wczytania obu plików panel jest powiadamiany o tym fakcie za pomocą wiadomości editor.load oraz payloadu zawierającego wczytane dane.

Metoda fetch NavigatorConfigHandlera zwraca prócz zawartości pliku konfiguracyjnego również sparsowane dane:

Natomiast analogiczna metoda w przypadku obiektu injectScriptFile dodatkowo stara się wyekstraktować lokalny i zewnętrzny adres IP:

Kolejnym krokiem jest zainicjalizowanie dodatkowego przycisku powiązanego z rozszerzeniem:

…no i samego interfejsu użytkownika wraz z dodatkowymi bibliotekami i logiką jego działania:

Po obsłużeniu interfejsu użytkownika inicjalizowany jest obiekt odpowiedzialny za monitorowanie zmian zewnętrznego adresu IP. W ramach „konstruktora” obiektu definiowane są dwie funkcje: onInit obsługująca pierwsze sprawdzenie adresu i onChange definiująca, co się ma stać w przypadku zmiany adresu w trakcie działania rozszerzenia:

Po wykonaniu tego należy tylko uruchomić monitoring po odpowiedniej informacji z panelu:

Metoda start() sprawia, że wywoływana jest funkcja fetchRemoteAddress, która odpytuje adres https://api.ipify.org/?format=json zwracający zewnętrzne IP. W przypadku gdy API zwróci prawidłową odpowiedź, wywoływany jest callback, który następnie wywoła (yo dawg!) wcześniej przekazaną do konstruktora funkcję onInit wraz z odpowiednimi argumentami. Następnie za pomocą funkcji setInterval cyklicznie wywoływana będzie funkcja performChangeCheck, która w przypadku zmiany adresu IP wywoła wcześniej przekazaną funkcji onChange. Jak widać, kto pisał w JavaScripcie, ten w cyrku się nie śmieje.

Przypadek? Nie sondzem!

Następnie ustawiany jest handler mający na celu obsługę przypadku, w którym użytkownik chciałby zmienić spoofowany adres IP bądź też uruchomić którąś z proponowanych przez rozszerzenie stron do sprawdzania stopnia swojej podatności na fingerprintowanie / wyciek informacji:

Na koniec pozostaje przeanalizować kluczowy element rozszerzenia  realizujący większość jego funkcji:

Co się dzieje w funkcji register?

Jak widać w powyższym kodzie rejestrowane są usługi (Services.obs.addObserver) obserwujące pewien typ zdarzeń występujących  w przeglądarce. Jeśli jakiekolwiek zdarzenie danego typu będzie miało miejsce podczas działania rozszerzenia, spowoduje to wywołanie metody observe zdefiniowanej w przekazywanym obiekcie observerHandler. Jako drugi argument do funkcji rejestrującej obserwatora podawany jest typ zdarzenia. Dla powyższego przykładu są to odpowiednio:

  • content-document-global-created
    Wysyłany bezpośrednio po tym, jak utworzony zostanie obiekt DOM Window, ale przed wywołaniem na nich jakichkolwiek skryptów. W praktyce zdarzenie to jest wykorzystywane do wstrzyknięcia własnego API do DOM Window. Przez właśnie ten obiekt odwołuje się do API wykorzystywanych do fingerprintigu, np. User-Agenta.
  • http-on-modify-request
    Wysyłany w momencie wykonywania żadania HTTP. Może być używany do podmiany nagłówków żądania.
  • http-on-opening-request
    Bardzo podobny do poprzedniego zdarzenia, wysyłany troszeczkę wcześniej niż w poprzednim wypadku. Trzeci argument (boolean) mówi o tym, czy referencja do funkcji observerHandler jest mocna czy słaba.

Zatem teraz przyjrzyjmy się obiektowi observerHandler:

Analizę tego obiektu należy zacząć od metody observe. Jako argumenty przyjmuje ona:

  • subject
    czyli obiekt, którego dotyczyła dana akcja lub obserwacja, np. obiekt reprezentujący nagłówki HTTP,
  • topic
    typ zaobserwowanej zmiany lub akcji, np. wysłanie żądania HTTP,
  • data
    dodatkowe dane powiązane ze zmianą lub akcją.

W naszym przypadku funkcja observe pełni rolę prostego routera rozdysponowującego zdarzenia dotyczące wysłania żądania HTTP do funkcji observeRequest, natomiast zdarzenia dotyczące załadowania strony do observeDocument.

Funkcja observeRequest na podstawie danych wczytanych z wcześniej analizowanego pliku jsoverrider.json nadpisuje nagłówki HTTP dotyczące User-Agenta i akceptowanych języków. Wykonuje się to za metody setRequestHeader interfejsu nsIHttpChannel.

Funkcja observeDocument jest nieco bardziej skomplikowana. W pierwszym kroku pobiera na podstawie parametru subject obiekt window prawie załadowanej strony (skrypty jeszcze nie zdążyły się uruchomić). Następnie tworzy sandbox – obiekt reprezentujący środowisko wykonania JS odizolowany od oryginalnej strony. Sandbox ten tworzony jest na podstawie wcześniej uzyskanego obiektu window pozyskanego z oryginalnej strony (zawiera pełną kopię obiektu window – parametr sandboxPrototype: window). Sandbox działa też z wyłączonym „Xray vision”.

Ciekawostka mostka

„Xray vision” to mechanizm mający na celu, w bardzo dużym uproszczeniu, zwrócenie oryginalnych wartości zawartości DOM API w przypadku utworzonego przez użytkownika kontekstu wykonania. Mówiąc po ludzku:

– domyślnie Window.alert(„Nie lubie javascriptu”) zwróci okno z komunikatem „Nie lubie javascriptu”,
– w JavaScripcie można nadpisać dużo rzeczy, w tym funkcje alert, np: window.alert = function(text) { console.log(„Pisanie w tym języku przyprawia mnie o ból głowy – https://github.com/miguelmota/javascript-idiosyncrasies”) };
– po tej operacji Window.alert(„Nie lubie javascript”) wypisze nam „Pisanie w tym języku przyprawia mnie o ból głowy – https://github.com/miguelmota/javascript-idiosyncrasies” w konsoli,
– włączając mechanizm „Xray vision” przy tworzeniu sandboxu, jak w przypadku rozszerzenia, uzyskamy jednak oryginalne zachowanie window.alert().

Więcej na temat tego mechanizmu można znaleźć tu.

W przypadku gdy operacja tworzenia sandboxu powiodła się, zostaje dwukrotnie wywołana funkcja evalInSandbox, dowolny kod JavaScript w podanym sanboxie. W pierwszym przypadku wykonywany jest kod, który jest wywołaniem funkcji override, do której jako parametr json przekazywana jest zawartość wcześniej opisanego pliku jsoverrider.json:

Drugie wywołanie evalInSandbox de facto wstrzykuje do kontekstu otworzonej strony WWW kod znajdujący się w pliku jsoverrider.js. Ot, cała tajemnica działania Antidetecta!

Podsumowanie

Po przeczytaniu powyższego tekstu odbiorca artykułu powinien posiadać w mniemaniu autora przynajmniej mgliste pojęcie, w jaki sposób działa najpopularniejsze narzędzie do omijania fingerpintowania (Antidetect). Czytelnika zapewne zacznie nurtować w tym miejscu następująca zagwozdka: „Skoro już wiem, jak wyglądają programy do antyfingerpintingu, to jak wygląda ekosystem biznesowy, jaki wokół nich się wykształcił?” By odpowiedzieć na to pytanie, niezwykle proaktywny autor zaprasza do następnej, ostatniej (uf!) już części artykułu.

Marcin Mostek
Nethone