Jak trojan Android Gustuff wyciąga pieniądze (fiat i kryptowaluty) z twoich kont

Jak trojan Android Gustuff wyciąga pieniądze (fiat i kryptowaluty) z twoich kont

Niedawno Group-IB informowała przedstawił informacje o działalności mobilnego androidowego trojana Gustuff. Działa on wyłącznie na rynkach międzynarodowych, atakując klientów 100 największych zagranicznych banków, użytkowników 32 portfeli kryptowalutowych oraz dużych zasobów e-commerce. Twórca Gustuff to rosyjskojęzyczny cyberprzestępca znany jako Bestoffer. Jeszcze niedawno chwalił swój trojan jako „poważny produkt dla ludzi z wiedzą i doświadczeniem”.

Specjalista ds. analizy złośliwego oprogramowania z Group-IB Iwan Pisariew w swoim badaniu szczegółowo opisuje, jak działa Gustuff i jakie niesie zagrożenia.

Na kogo poluje Gustuff

Gustuff należy do nowego pokolenia złośliwego oprogramowania z całkowicie zautomatyzowanymi funkcjami. Według twórcy, trojan stał się nową, ulepszoną wersją złośliwej aplikacji AndyBot, która od listopada 2017 roku atakuje telefony z systemem Android i kradnie pieniądze za pośrednictwem phishingowych formularzy internetowych, udających mobilne aplikacje znanych międzynarodowych banków i systemów płatniczych. Bestoffer informował, że cena wynajmu „Gustuff Bot” wynosiła 800 dolarów miesięcznie.

Analiza próbki Gustuff wykazała, że potencjalnie trojan celuje w klientów korzystających z aplikacji mobilnych największych banków, takich jak Bank of America, Bank of Scotland, J.P.Morgan, Wells Fargo, Capital One, TD Bank, PNC Bank, a także w portfele kryptowalutowe Bitcoin Wallet, BitPay, Cryptopay, Coinbase i inne.

Początkowo stworzony jako klasyczny trojan bankowy, w obecnej wersji Gustuff znacznie rozszerzył listę potencjalnych obiektów ataku. Oprócz aplikacji bankowych, fintechowych i kryptowalutowych, Gustuff celuje również w użytkowników aplikacji rynków, sklepów internetowych, systemów płatności i komunikatorów. W szczególności PayPal, Western Union, eBay, Walmart, Skype, WhatsApp, Gett Taxi, Revolut i innych.

Punkt wejścia: zakłada masowe zarażenie

Gustuff charakteryzuje się "klasycznym" wektorem penetracji na smartfony z systemem Android poprzez SMS-y zawierające linki do APK. Po zainfekowaniu urządzenia Android złośliwym oprogramowaniem, na polecenie serwera może nastąpić dalsze rozprzestrzenienie Gustuffa w bazie kontaktów zainfekowanego telefonu lub w bazie danych serwera. Funkcjonalność Gustuffa jest zaprojektowana do masowego zarażania i maksymalizacji zysków swoich operatorów – zawiera unikalną funkcję "autozalewania" w legalne aplikacje mobilne banków i portfele kryptowalutowe, co umożliwia szybkie i skalowalne kradzieże pieniędzy.

Badania trojana wykazały, że funkcja autodoładowania jest implementowana za pomocą Accessibility Service – usługi dla osób z ograniczeniami. Gustuff nie jest pierwszym trojanem, który skutecznie omija ochronę interakcji z elementami okien innych aplikacji za pomocą tej usługi Android. Jednak użycie Accessibility Service w połączeniu z autodoładowaniem pozostaje wciąż dość rzadkim zjawiskiem.

Po pobraniu na telefon ofiary Gustuff, korzystając z Accessibility Service, zyskuje możliwość interakcji z elementami okien innych aplikacji (bankowych, kryptowalutowych oraz aplikacji do zakupów online, komunikacji itp.), wykonując działania niezbędne dla przestępców. Na przykład, na polecenie serwera trojan może naciskać przyciski i zmieniać wartości pól tekstowych w aplikacjach bankowych. Użycie mechanizmu Accessibility Service pozwala trojanowi omijać mechanizmy ochrony stosowane przez banki do przeciwdziałania mobilnym trojanom poprzedniej generacji oraz zmiany w polityce bezpieczeństwa wprowadzone przez Google w nowych wersjach systemu Android. Gustuff potrafi "wyłączać" ochronę Google Protect: według zapewnień autora, ta funkcja działa w 70% przypadków.

Jak trojan Android Gustuff wyciąga pieniądze (fiat i kryptowaluty) z twoich kont

Gustuff może także wyświetlać fałszywe powiadomienia PUSH z ikonami prawdziwych aplikacji mobilnych. Użytkownik klika w powiadomienie PUSH i widzi załadowane z serwera okno phishingowe, do którego sam wprowadza wymagane dane karty bankowej lub portfela kryptowalut. W innej metodzie działania Gustuff wpływa na otwarcie aplikacji, pod nazwą której zostało wyświetlone powiadomienie PUSH. W tym przypadku złośliwe oprogramowanie na polecenie serwera poprzez Accessibility Service może wypełniać pola formularza aplikacji bankowej dla oszukańczej transakcji.

Funkcje Gustuff obejmują również przesyłanie do serwera informacji o zainfekowanym urządzeniu, możliwość odczytu/wysyłania wiadomości SMS, wysyłanie zapytań USSD, uruchamianie SOCKS5 Proxy, przechodzenie do linków, przesyłanie plików (w tym skanów dokumentów, zrzutów ekranu, zdjęć) na serwer oraz resetowanie urządzenia do ustawień fabrycznych.

Analiza złośliwego oprogramowania

Przed zainstalowaniem złośliwej aplikacji system Android wyświetla okno zawierające listę uprawnień wymaganych przez Gustuffa:

Jak trojan Android Gustuff wyciąga pieniądze (fiat i kryptowaluty) z twoich kont
Instalacja aplikacji nastąpi tylko po uzyskaniu zgody użytkownika. Po uruchomieniu aplikacji trojan wyświetli użytkownikowi okno:

Jak trojan Android Gustuff wyciąga pieniądze (fiat i kryptowaluty) z twoich kont
Po czym usunie swoją ikonę.

Gustuff jest zapakowany, według autora, przez pakietera FTT. Po uruchomieniu aplikacja okresowo łączy się z serwerem CnC w celu otrzymania komend. W kilku badanych przez nas plikach jako serwer kontrolny używany był adres IP 88.99.171[.]105 (w dalszej części będziemy go nazywać <%CnC%>).

Po uruchomieniu program zaczyna wysyłać wiadomości do serwera http://<%CnC%>/api/v1/get.php.

Oczekiwanym odpowiedzią jest JSON w następującym formacie:

{
    "results" : "OK",
    "command":{
        "id": "<%id%>",
        "command":"<%command%>",
        "timestamp":"<%Server Timestamp%>",
        "params":{
		<%Command parameters as JSON%>
        },
    },
}

Przy każdym połączeniu aplikacja przesyła informacje o zainfekowanym urządzeniu. Format wiadomości przedstawiony jest poniżej. Należy zauważyć, że pola full, extra, apps i permission są opcjonalne i będą przesyłane tylko w przypadku zapytania z CnC.

{
 "info":
 {
 "info":
 {
 "cell":<%Sim operator name%>,
 "country":<%Country ISO%>,
 "imei":<%IMEI%>,
 "number":<%Phone number%>,
 "line1Number":<%Phone number%>,
 "advertisementId":<%ID%>
 },
 "state":
 {
 "admin":<%Has admin rights%>,
 "source":<%String%>,
 "needPermissions":<%Application needs permissions%>,
 "accesByName":<%Boolean%>,
 "accesByService":<%Boolean%>,
 "safetyNet":<%String%>,
 "defaultSmsApp":<fault Sms Application%>,
 "isDefaultSmsApp":<%Current application is Default Sms Application%>,
 "dateTime":<%Current date time%>,
 "batteryLevel":<ttery level%>
 },
 "socks":
 {
 "id":<%Proxy module ID%>,
 "enabled":<%Is enabled%>,
 "active":<%Is active%>
 },
 "version":
 {
 "versionName":<%Package Version Name%>,
 "versionCode":<%Package Version Code%>,
 "lastUpdateTime":<%Package Last Update Time%>,
 "tag":<%Tag, default value: "TAG"%>,
 "targetSdkVersion":<%Target Sdk Version%>,
 "buildConfigTimestamp":1541309066721
 },
 },
 "full":
 {
 "model":<vice Model%>,
 "localeCountry":<%Country%>,
 "localeLang":<%Locale language%>,
 "accounts":<%JSON array, contains from "name" and "type" of accounts%>,
 "lockType":<%Type of lockscreen password%>
 },
 "extra":
 {
 "serial":<%Build serial number%>,
 "board":<%Build Board%>,
 "brand":<%Build Brand%>,
 "user":<%Build User%>,
 "device":<%Build Device%>,
 "display":<%Build Display%>,
 "id":<%Build ID%>,
 "manufacturer":<%Build manufacturer%>,
 "model":<%Build model%>,
 "product":<%Build product%>,
 "tags":<%Build tags%>,
 "type":<%Build type%>,
 "imei":<%imei%>,
 "imsi":<%imsi%>,
 "line1number":<%phonenumber%>,
 "iccid":<%Sim serial number%>,
 "mcc":<%Mobile country code of operator%>,
 "mnc":<%Mobile network code of operator%>,
 "cellid":<%GSM-data%>,
 "lac":<%GSM-data%>,
 "androidid":<%Android Id%>,
 "ssid":<%Wi-Fi SSID%>
 },
 "apps":{<%List of installed applications%>},
 "permission":<%List of granted permissions%>
} 

Przechowywanie danych konfiguracyjnych

Gustuff przechowuje ważne informacje w pliku preferencji. Nazwa pliku oraz nazwy parametrów w nim są wynikiem obliczenia sumy MD5 z ciągu 15413090667214.6.1<%name%>, gdzie <%name%> — oryginalna para nazwa-wartość. Interpretacja funkcji generującej nazwę w Pythonie:

 nameGenerator(input):
    output = md5("15413090667214.6.1" + input) 

W dalszej części będziemy to oznaczać jako nameGenerator(input).
W ten sposób, nazwa pierwszego pliku: nameGenerator(«API_SERVER_LIST»), zawiera wartości o następujących nazwach:

Nazwa zmiennejWartość
nameGenerator(«API_SERVER_LIST»)Zawiera listę adresów CnC w postaci tablicy.
nameGenerator(«API_SERVER_URL»)Zawiera adres CnC.
nameGenerator(«SMS_UPLOAD»)Flaga jest ustawiona domyślnie. Jeśli flaga jest włączona – wysyła wiadomości SMS do CnC.
nameGenerator(«SMS_ROOT_NUMBER»)Numer telefonu, na który będą wysyłane SMS-y za pomocą zainfekowanego urządzenia. Domyślnie null.
nameGenerator(«SMS_ROOT_NUMBER_RESEND»)Flaga domyślna jest wyłączona. Jeśli jest ustawiona – po otrzymaniu SMS-a na zainfekowane urządzenie, zostanie on wysłany na numer główny.
nameGenerator(«DEFAULT_APP_SMS»)Flaga domyślna jest wyłączona. Jeśli ta flaga jest ustawiona – aplikacja będzie przetwarzać przychodzące wiadomości SMS.
nameGenerator(«DEFAULT_ADMIN»)Flaga domyślna jest wyłączona. Jeśli flaga jest ustawiona – aplikacja ma uprawnienia administratora.
nameGenerator(«DEFAULT_ACCESSIBILITY»)Flaga domyślna jest wyłączona. Jeśli flaga jest ustawiona – uruchomiona zostaje usługa korzystająca z Accessibility Service.
nameGenerator(«APPS_CONFIG»)Obiekt JSON, zawiera listę działań, które należy wykonać przy wystąpieniu zdarzenia Accessibility związanym z danym aplikacją.
nameGenerator(«APPS_INSTALLED»)Przechowuje listę aplikacji zainstalowanych na urządzeniu.
nameGenerator(«IS_FIST_RUN»)Flaga przy pierwszym uruchomieniu jest resetowana.
nameGenerator(«UNIQUE_ID»)Zawiera unikalny identyfikator. Generowany przy pierwszym uruchomieniu bota.

Moduł przetwarzania poleceń od serwera

Aplikacja przechowuje adresy serwerów CnC w postaci tablicy zakodowanych w Base85 łańcuchów. Lista CnC — serwerów może być zmieniona przy otrzymaniu odpowiedniego polecenia, w takim przypadku adresy będą przechowywane w pliku preferencji.

W odpowiedzi na żądanie serwer przesyła aplikacji polecenie. Należy zaznaczyć, że polecenia i parametry są przedstawione w formacie JSON. Aplikacja może przetwarzać następujące polecenia:

ZespółOpis
forwardStartRozpocznij przesyłanie otrzymywanych wiadomości SMS zainfekowanego urządzenia na serwer CnC.
forwardStopZatrzymaj przesyłanie otrzymywanych wiadomości SMS zainfekowanego urządzenia na serwer CnC.
ussdRunWykonaj zapytanie USSD. Numer, na który należy wykonać zapytanie USSD, znajduje się w polu JSON „number”.
sendSmsWyślij jedną wiadomość SMS (jeśli to konieczne, wiadomość jest „dzielona” na części). Jako parametr polecenie przyjmuje obiekt JSON zawierający pola „to” — numer odbiorcy i „body” — treść wiadomości.
sendSmsAbWyślij wiadomości SMS (jeśli to konieczne, wiadomość jest „dzielona” na części) do wszystkich z listy kontaktów zainfekowanego urządzenia. Interwał między wysyłaniem wiadomości wynosi 10 sekund. Treść wiadomości znajduje się w polu JSON „body”.
sendSmsMassWysyłaj SMS-y (jeśli to konieczne, wiadomość zostaje podzielona na części) do kontaktów podanych w parametrach polecenia. Interwał między wysyłaniem wiadomości wynosi 10 sekund. Jako parametr polecenie przyjmuje tablicę JSON (pole „sms”), której elementy zawierają pola „to” — numer docelowy i „body” — treść wiadomości.
changeServerTo polecenie jako parametr może przyjmować wartość z kluczem „url” — wtedy bot zmieni wartość nameGenerator(„SERVER_URL”), lub „array” — wtedy bot zapisze tablicę w nameGenerator(„API_SERVER_LIST”). W ten sposób aplikacja zmienia adresy serwerów CnC.
adminNumberPolecenie przeznaczone jest do pracy z numerem root. Polecenie przyjmuje obiekt JSON z następującymi parametrami: „number” — zmienić nameGenerator(„ROOT_NUMBER”) na otrzymaną wartość, „resend” — zmienić nameGenerator(„SMS_ROOT_NUMBER_RESEND”), „sendId” — wysłać na nameGenerator(„ROOT_NUMBER”) uniqueID.
updateInfoWyślij na serwer informacje o zarażonym urządzeniu.
wipeDataPolecenie przeznaczone do usuwania danych użytkownika. W zależności od tego, pod jaką nazwą została uruchomiona aplikacja, następuje albo całkowite wymazanie danych z ponownym uruchomieniem urządzenia (primary user), albo usunięcie tylko danych użytkownika (secondary user).
socksStartUruchom moduł Proxy. Działanie modułu opisano w osobnej sekcji.
socksStopZatrzymaj działanie modułu Proxy.
openLinkPrzejdź pod link. Link znajduje się w parametrze JSON pod kluczem „url”. Do otwarcia linku używana jest „android.intent.action.VIEW”.
uploadAllSmsWyślij na serwer wszystkie SMS-y odebrane przez urządzenie.
uploadAllPhotosWyślij na URL zdjęcia z zarażonego urządzenia. URL przychodzi jako parametr.
uploadFileWyślij na URL plik z zarażonego urządzenia. URL przychodzi jako parametr.
uploadPhoneNumbersWyślij na serwer numery telefonów z listy kontaktów. Jeśli jako parametr przychodzi obiekt JSON z wartością pod kluczem „ab”, aplikacja otrzymuje listę kontaktów z książki telefonicznej. Jeśli jako parametr przychodzi obiekt JSON z kluczem „sms”, aplikacja odczytuje listę kontaktów z nadawców SMS-ów.
changeArchiveAplikacja pobiera plik z adresu, który jest przesyłany jako parametr pod kluczem „url”. Pobrany plik jest zapisywany pod nazwą „archive.zip”. Następnie aplikacja dekompresuje plik, w razie potrzeby używając hasła do archiwum „b5jXh37gxgHBrZhQ4j3D”. Rozpakowane pliki są zapisywane w katalogu [external storage]/hgps. W tym katalogu aplikacja przechowuje web-fałszywki (opisane poniżej).
akcjePolecenie jest przeznaczone do pracy z Usługą Akcji, która jest opisana w osobnej sekcji.
testNic nie robi.
pobierzPolecenie jest przeznaczone do pobrania pliku z zdalnego serwera i zapisania go w katalogu „Downloads”. URL i nazwa pliku są przekazywane jako parametry, pola w obiekcie JSON jako „url” i „fileName”.
usuńUsuwa plik z katalogu „Downloads”. Nazwa pliku jest przekazywana w parametrze JSON pod kluczem „fileName”. Domyślna nazwa pliku to „tmp.apk”.
powiadomienieWyświetla powiadomienie z tekstami opisu i tytułu, określonymi przez serwer zarządzający.

Format polecenia powiadomienie:

{
    "results" : "OK",
    "command":{
    "id": ,
    "command":"powiadomienie",
    "timestamp":,
    "params":{
        "openApp":,
        "array": [
                      {"title": ,
                      "desc": ,
                      "app":}
                   ]
                   },
        },
}

Powiadomienie generowane przez badaną aplikację wygląda identycznie jak powiadomienia generowane przez aplikację określoną w polu app. Jeśli wartość pola openApp — True, otwarcie powiadomienia uruchamia aplikację określoną w polu app. Jeśli wartość pola openApp — False, wtedy:

  • otwiera się okno typu phishing, a jego zawartość jest pobierana z katalogu /hgps/
  • otwiera się okno typu phishing, a jego zawartość jest pobierana z serwera ?id=&app=
  • otwiera się okno typu phishing, zamaskowane pod Google Play Card, z możliwością wprowadzenia danych karty.

Wynik wykonania dowolnego polecenia aplikacja wysyła do set_state.php w formie obiektu JSON w następującym formacie:

{
    "command":
    {
        "command":,
        "id":,
        "state":
    }
    "id":
}

ActionsService
Lista poleceń, które obsługuje aplikacja, obejmuje akcja. Po otrzymaniu polecenia moduł przetwarzania poleceń zwraca się do tej usługi w celu realizacji rozszerzonego polecenia. Usługa przyjmuje jako parametr obiekt JSON. Usługa może realizować następujące polecenia:

1. PARAMS_ACTION — przy otrzymaniu takiej komendy, serwis w pierwszej kolejności pobiera z parametru JSON wartość według klucza Type, która może być następująca:

  • serviceInfo – podkomenda pobiera z parametru JSON wartość według klucza includeNotImportant. Jeśli flaga jest równa True — aplikacja ustawia flagę FLAG_ISOLATED_PROCESS na serwisie, wykorzystującym Accessibility Service. W ten sposób serwis zostanie uruchomiony w osobnym procesie.
  • root — uzyskać i wysłać na serwer informacje o oknie, które aktualnie jest w fokusie. Aplikacja uzyskuje informacje za pomocą klasy AccessibilityNodeInfo.
  • admin — zażądać praw administratora.
  • delay — wstrzymać działanie ActionsService na liczbę milisekund, która jest określona w parametrze według klucza „data”.
  • windows — wysłać listę widocznych dla użytkownika okien.
  • install — zainstalować aplikację na zainfekowane urządzenie. Nazwa pakietu archiwum znajduje się w kluczu „fileName”. Same archiwum znajduje się w katalogu Downloads.
  • global – podkomenda przeznaczona do przejścia z bieżącego okna:
    • do menu Ustawienia Szybkie
    • wstecz
    • do głównej strony
    • do powiadomień
    • do okna ostatnio otwartych aplikacji

  • launch — uruchomić aplikację. Nazwa aplikacji jest przekazywana jako parametr według klucza data.
  • sounds — zmienić tryb dźwięku na ciszę.
  • unlock — zwiększa jasność ekranu i klawiatury do maksimum. Aplikacja wykonuje tę akcję za pomocą WakeLock, jako tag podaje napis [Application lable]:INFO
  • permissionOverlay — funkcja nie została zaimplementowana (odpowiedź na wykonanie komendy — {„message”:„Not support”} lub {„message”:„low sdk”})
  • gesture — funkcja nie została zaimplementowana (odpowiedź na wykonanie komendy — {„message”:„Not support”} lub {„message”:„Low API”})
  • permissions — ta komenda jest potrzebna do zażądania praw dla aplikacji. Jednak funkcja żądania nie została zaimplementowana, w związku z tym komenda nie ma sensu. Lista żądanych praw przychodzi jako tablica JSON z kluczem „permissions”. Standardowa lista:
    • android.permission.READ_PHONE_STATE
    • android.permission.READ_CONTACTS
    • android.permission.CALL_PHONE
    • android.permission.RECEIVE_SMS
    • android.permission.SEND_SMS
    • android.permission.READ_SMS
    • android.permission.READ_EXTERNAL_STORAGE
    • android.permission.WRITE_EXTERNAL_STORAGE

  • open — wyświetlić na ekranie okno phishingowe. W zależności od wartości parametru przekazanego przez serwer, aplikacja może zademonstrować następujące okna phishingowe:
    • Wyświetl okno phishingowe, którego zawartość jest opisana w pliku w katalogu /hgps/Wynik interakcji użytkownika z oknem zostanie wysłany na adres /records.php
    • Wyświetl okno phishingowe, którego zawartość jest wstępnie ładowana z adresu ?id=&app=Wynik interakcji użytkownika z oknem zostanie wysłany na adres /records.php
    • Wyświetl okno phishingowe, zamaskowane jako karta Google Play.

  • interaktywny — komenda przeznaczona do interakcji z elementami okien innych aplikacji przy użyciu AccessibilityService. Do interakcji w aplikacji zaimplementowano specjalną usługę. Badana aplikacja może współdziałać z oknami:
    • Aktualnie aktywnym. W takim przypadku parametr zawiera id lub text (nazwa) obiektu, z którym należy współdziałać.
    • Widocznymi dla użytkownika w momencie wykonania komendy. Aplikacja wybiera okna według id.

    Otrzymawszy obiekty AccessibilityNodeInfo dla interesujących elementów okna, aplikacja w zależności od parametrów może wykonać działania:

    • focus — ustawić fokus na obiekt.
    • click — kliknąć obiekt.
    • actionId — wykonać działanie według ID.
    • setText — zmienić tekst obiektu. Zmiana tekstu jest możliwa na dwa sposoby: poprzez wykonanie akcji ACTION_SET_TEXT (jeśli wersja Androida zainfekowanego urządzenia jest niższa lub równa LOLLIPOP), lub umieszczając ciąg w schowku i wklejając go do obiektu (dla wersji wyższych). Ta komenda może być używana do zmiany danych w aplikacji bankowej.

2. PARAMS_ACTIONS — to samo co PARAMS_ACTION, tylko przychodzi jako tablica JSON komend.

Wydaje się, że wielu będzie ciekawiło, jak wyglądają funkcje interakcji z elementami okna innej aplikacji. Oto jak zrealizowana jest ta funkcjonalność w Gustuffie:

boolean interactiveAction(List aiList, JSONObject action, JsonObject res) {
    int count = action.optInt("repeat", 1);
    Iterator aiListIterator = ((Iterable)aiList).iterator();
    int count = 0;
    while(aiListIterator.hasNext()) {
        Object ani = aiListIterator.next();
        if(1 <= count) {
            int index;
            for(index = 1; true; ++index) {
                if(action.has("focus")) {
                    if(((AccessibilityNodeInfo)ani).performAction(1)) {
                        ++count;
                    }
                }
                else if(action.has("click")) {
                    if(((AccessibilityNodeInfo)ani).performAction(16)) {
                        ++count;
                    }
                }
                else if(action.has("actionId")) {
                    if(((AccessibilityNodeInfo)ani).performAction(action.optInt("actionId"))) {
                        ++count;
                    }
                }
                else if(action.has("setText")) {
                    customHeader ch = CustomAccessibilityService.a;
                    Context context = this.getApplicationContext();
                    String text = action.optString("setText");
                    if(performSetTextAction(ch, context, ((AccessibilityNodeInfo)ani), text)) {
                        ++count;
                    }
                }
                if(index == count) {
                    break;
                }
            }
        }
        ((AccessibilityNodeInfo)ani).recycle();
    }
    res.addPropertyNumber("res", Integer.valueOf(count));
}

Funkcja zamiany tekstu:

boolean performSetTextAction(Context context, AccessibilityNodeInfo ani, String text) {
    boolean result;
    if(Build$VERSION.SDK_INT >= 21) {
        Bundle b = new Bundle();
        b.putCharSequence("ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE", ((CharSequence)text));
        result = ani.performAction(0x200000, b);  // ACTION_SET_TEXT
    }
    else {
        Object clipboard = context.getSystemService("clipboard");
        if(clipboard != null) {
        ((ClipboardManager)clipboard).setPrimaryClip(ClipData.newPlainText("autofill_pm", ((CharSequence)text)));
        result = ani.performAction(0x8000);  // ACTION_PASTE
        }
        else {
            result = false;
        }
    }
    return result;
}

W odpowiednich ustawieniach serwera sterującego, Gustuff jest w stanie wypełniać pola tekstowe w aplikacji bankowej oraz klikać na potrzebne przyciski do przeprowadzenia transakcji. Złośliwe oprogramowanie nie musi nawet przechodzić autoryzacji w aplikacji — wystarczy wysłać komendę do demonstracji powiadomienia PUSH z otwarciem wcześniej zainstalowanej aplikacji bankowej. Użytkownik sam przechodzi autoryzację, po czym Gustuff będzie mógł przeprowadzić automatyczne wypełnienie.

Moduł obsługi SMS-ów

Aplikacja ustawia obsługę zdarzenia na odbieranie SMS-ów przez zainfekowane urządzenie. Badana aplikacja może odbierać polecenia od operatora, które przychodzą w treści SMS-a. Polecenia przychodzą w formacie:

7!5=

Aplikacja przeszukuje wszystkie przychodzące SMS-y w poszukiwaniu ciągu 7!5=, po wykryciu linii – dekoduje z Base64 ciąg z przesunięciem 4 i wykonuje polecenie. Polecenia są podobne do poleceń z CnC. Wynik wykonania jest wysyłany na ten sam numer, z którego przyszło polecenie. Format odpowiedzi:

7*5=

Opcjonalnie aplikacja może wysyłać wszystkie odbierane wiadomości na numer Root. W tym celu w pliku preference musi być podany numer Root i ustawiona flaga przekierowania wiadomości. Wiadomość SMS jest wysyłana na numer przestępcy w formacie:

Dodatkowo aplikacja może opcjonalnie wysyłać wiadomości do CnC. Wiadomość SMS jest wysyłana na serwer w formacie JSON:

{
    "id":,
    "sms":
    {
        "text":,
        "number":,
        "date":
    }
}

Jeśli flaga jest ustawiona nameGenerator(«DEFAULT_APP_SMS») – aplikacja przerywa przetwarzanie wiadomości SMS i czyści listę odebranych wiadomości.

Moduł Proxy

W badanej aplikacji znajduje się moduł Backconnect Proxy (dalej Moduł Proxy), który ma oddzielną klasę, zawierającą statyczne pola z konfiguracją. Dane konfiguracyjne są przechowywane w próbce w formie otwartej:

Jak trojan Android Gustuff wyciąga pieniądze (fiat i kryptowaluty) z twoich kont

Wszystkie działania podejmowane przez Moduł Proxy są rejestrowane w plikach. W tym celu aplikacja w External Storage tworzy katalog o nazwie „logs” (pole ProxyConfigClass.logsDir w klasie konfiguracyjnej), w którym przechowywane są pliki logów. Logowanie odbywa się w plikach o nazwach:

  1. main.txt – do tego pliku rejestrowana jest praca klasy o nazwie CommandServer. W późniejszym etapie logowanie linii str do tego pliku będziemy oznaczać jako mainLog(str).
  2. session-.txt — do tego pliku zapisywane są dane logów związane z określoną sesją proxy. W późniejszym etapie logowanie linii str do tego pliku będziemy oznaczać jako sessionLog(str).
  3. server.txt – do tego pliku rejestrowane są wszystkie dane zapisywane w powyżej opisanych plikach.

Format danych logów:

[Thread[], id[]]: log-string

Występujące w trakcie pracy Modułu Proxy wyjątki również są rejestrowane w pliku. W tym celu aplikacja tworzy obiekt JSON w formacie:

{
 "uncaughtException":
 "thread":
 "message":
 "trace": //Stack trace info
 [
 {
 "ClassName":
 "FileName":
 "LineNumber":
 "MethodName":
 },
 {
 "ClassName":
 "FileName":
 "LineNumber":
 "MethodName":
 }
 ]
}

Następnie konwertuje go na reprezentację tekstową i loguje.

Uruchomienie modułu Proxy następuje po otrzymaniu odpowiedniej komendy. Po otrzymaniu polecenia uruchomienia modułu Proxy, aplikacja uruchamia usługę o nazwie MainService, która odpowiada za zarządzanie pracą modułu Proxy – jego uruchamianie i zatrzymywanie.

Etapy uruchamiania usługi:

1. Uruchamia timer, który działa raz na minutę i sprawdza aktywność modułu Proxy. Jeśli moduł nie jest aktywny – uruchamia go.
Również w przypadku wystąpienia zdarzenia android.net.conn.CONNECTIVITY_CHANGE moduł Proxy zostaje uruchomiony.

2. Aplikacja tworzy wake-lock z parametrem PARTIAL_WAKE_LOCK i go przejmuje. W ten sposób nie pozwala procesorowi urządzenia przejść w tryb uśpienia.

3. Uruchamia klasę przetwarzania poleceń modułu Proxy, wcześniej logując ciąg mainLog("start server") i

Server::start() host[], commandPort[], proxyPort[]

gdzie proxy_cnc, command_port i proxy_port – parametry pochodzące z konfiguracji serwera Proxy.

Klasa przetwarzania poleceń nosi nazwę CommandConnection. Zaraz po uruchomieniu wykonuje następujące czynności:

4. Łączy się z ProxyConfigClass.host: ProxyConfigClass.commandPort i wysyła tam dane o zainfekowanym urządzeniu w formacie JSON:

{
    "id":,
    "imei":,
    "imsi":,
    "model":,
    "manufacturer":,
    "androidVersion":,
    "country":,
    "partnerId":,
    "packageName":,
    "networkType":,
    "hasGsmSupport":,
    "simReady":,
    "simCountry":,
    "networkOperator":,
    "simOperator":,
    "version":
}

Gdzie:

  • id – identyfikator, próbuje uzyskać z pliku Shared Preference o nazwie „x” wartość z polem „id”. Jeśli nie uda się uzyskać tej wartości – generuje nową. W ten sposób moduł Proxy posiada swój identyfikator, który jest generowany analogicznie do Bot ID.
  • imei – IMEI urządzenia. Jeśli podczas uzyskiwania wartości wystąpił błąd – zamiast tego pola zostanie zapisany komunikat o błędzie.
  • imsi — Międzynarodowa tożsamość subskrybenta urządzenia. Jeśli podczas uzyskiwania wartości wystąpił błąd — zamiast tej pozycji zostanie zapisany komunikat o błędzie.
  • model — Widoczna dla użytkownika końcowego nazwa produktu końcowego.
  • manufacturer — Producent produktu/sprzętu (Build.MANUFACTURER).
  • androidVersion — ciąg w formacie „ (),”
  • country — aktualna lokalizacja urządzenia.
  • partnerId – pusty ciąg.
  • packageName – nazwa pakietu.
  • networkType — typ aktualnego połączenia sieciowego (przykład: „WIFI”, „MOBILE”). W przypadku błędu zwraca null.
  • hasGsmSupport – true – jeśli telefon obsługuje GSM, w przeciwnym razie false.
  • simReady – stan karty SIM.
  • simCountry — kod ISO kraju (na podstawie dostawcy karty SIM).
  • networkOperator — nazwa operatora. Jeśli podczas uzyskiwania wartości wystąpił błąd — zamiast tej pozycji zostanie zapisany komunikat o błędzie.
  • simOperator — Nazwa dostawcy usług (SPN). Jeśli podczas uzyskiwania wartości wystąpił błąd — zamiast tej pozycji zostanie zapisany komunikat o błędzie.
  • version — ta pozycja przechowuje wersję w klasie konfiguracyjnej, dla badanych wersji bota była równa „1.6”.

5. Przechodzi w tryb oczekiwania na polecenia z serwera. Polecenia z serwera przychodzą w formacie:

  • 0 offset – polecenie
  • 1 offset – sessionId
  • 2 offset – długość
  • 4 offset — dane

Gdy otrzymuje polecenie, aplikacja rejestruje:
mainLog("Header { sessionId, type[], length[] }")

Możliwe są następujące polecenia z serwera:

NazwaPolecenieDaneOpis
connectionId0Identyfikator połączeniaUtwórz nowe połączenie
SLEEP3CzasWstrzymaj działanie modułu Proxy
PING_PONG4Wyślij komunikat PONG

Komunikat PONG składa się z 4 bajtów i wygląda następująco: 0x04000000.

Gdy otrzymuje polecenie connectionId (do stworzenia nowego połączenia) CommandConnection tworzy instancję klasy ProxyConnection.

  • W procesie proxy biorą udział dwie klasy: ProxyConnection i end. Podczas tworzenia klasy ProxyConnection następuje połączenie z adresem ProxyConfigClass.host: ProxyConfigClass.proxyPort i przekazanie obiektu JSON:

 {
    "id":
}

W odpowiedzi serwer wysyła komunikat SOCKS5, który zawiera adres zdalnego serwera, z którym należy nawiązać połączenie. Interakcja z tym serwerem odbywa się za pomocą klasy end. Schematycznie nawiązanie połączenia można przedstawić w następujący sposób:

Jak trojan Android Gustuff wyciąga pieniądze (fiat i kryptowaluty) z twoich kont

Interakcje sieciowe

Aby zapobiec analizie ruchu przez sieciowe sniffery, interakcja pomiędzy serwerem CnC a aplikacją może być zabezpieczona za pomocą protokołu SSL. Wszystkie przesyłane dane zarówno z serwera, jak i do serwera są przedstawione w formacie JSON. W trakcie swojej pracy aplikacja wykonuje następujące zapytania:

  • http:///api/v1/set_state.php — wynik wykonania polecenia.
  • http://<%CnC%>/api/v1/get.php — odbieranie polecenia.
  • http:///api/v1/load_sms.php — pobieranie SMS-ów z zainfekowanego urządzenia.
  • http:///api/v1/load_ab.php — pobieranie listy kontaktów z zainfekowanego urządzenia.
  • http:///api/v1/aevents.php – zapytanie wykonywane podczas aktualizacji parametrów w pliku preferences.
  • http:///api/v1/set_card.php — przesyłanie danych zebranych przez okno phishingowe, podszywające się pod Google Play Market.
  • http:///api/v1/logs.php – pobieranie danych logów.
  • http:///api/v1/records.php – pobieranie danych zebranych przez okna phishingowe.
  • http:///api/v1/set_error.php – powiadamianie o wystąpieniu błędu.

Zalecenia

W celu ochrony swoich klientów przed zagrożeniem mobilnych trojanów, firmy powinny stosować kompleksowe rozwiązania, które pozwalają na śledzenie i ostrzeganie przed złośliwą aktywnością bez konieczności instalowania dodatkowego oprogramowania na urządzeniach użytkowników.

W tym celu metody detekcji trojanów mobilnych należy wzbogacić technologiami analizy zachowania zarówno klienta, jak i samej aplikacji. Ochrona powinna także zawierać funkcję identyfikacji urządzeń za pomocą technologii cyfrowego odcisku, co pozwoli na zrozumienie, kiedy konto jest używane z nietypowego urządzenia i mogło już wpaść w ręce oszustów.

Kluczowym aspektem jest możliwość analizy międzykanałowej, co daje firmom możliwość monitorowania ryzyk, które pojawiają się nie tylko po stronie Internetu, ale również mobilnego kanału, na przykład w aplikacjach do mobilnego bankowości, do operacji z kryptowalutami oraz wszelkich innych, w których mogą odbywać się transakcje finansowe.

Zasady bezpieczeństwa dla użytkowników:

  • nie instalować aplikacji na urządzenia mobilne z systemem Android z żadnych źródeł poza Google Play, zwracać szczególną uwagę na żądane uprawnienia aplikacji;
  • regularnie instalować aktualizacje systemu Android;
  • zwracać uwagę na rozszerzenia przesyłanych plików;
  • nie odwiedzać podejrzanych zasobów;
  • nie klikać w linki otrzymane w wiadomościach SMS.

Przy udziale Semeny Rohaczewa, młodszego specjalisty ds. badania złośliwego oprogramowania w Laboratorium Kryminalistyki Komputerowej Group-IB.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster