Zespół CERT Polska w ostatnich miesiącach zaobserwował nowe próbki mobilnego złośliwego systemu powiązane z atakiem NFC Relay (NGate) wymierzonym w użytkowników polskich banków.
Podstawowe informacje
Celem ataku jest umożliwienie nieuprawnionych wypłat gotówki z bankomatów z wykorzystaniem kart płatniczych ofiar. Przestępcy nie kradną fizycznie karty - przekazują ruch NFC karty z telefonu ofiary do urządzenia przestępcy stojącego przy bankomacie.
Jak to działa?
Socjotechnika/phishing - Ofiara dostaje wiadomość phishingową (e-mail/SMS) o rzekomym problemie technicznym lub incydencie bezpieczeństwa. Link prowadzi na stronę, która nakłania do instalacji aplikacji na Androida. Analizowana przez nas próbka była dystrybuowana przez files[.]fm/u/yfwsanu886

Telefon od "pracownika" banku - Oszust dzwoni, podając się za pracownika banku, aby „potwierdzić tożsamość” i uwiarygodnić instalację aplikacji. Użytkownik otrzymuje też SMS potwierdzający tożsamość rzekomego pracownika.

W aplikacji ofiara jest proszona o zweryfikowanie swojej karty płatniczej bezpośrednio w interfejsie. Musi przyłożyć fizyczną kartę do telefonu (NFC), a następnie wpisać PIN karty na ekranowej klawiaturze. Poniżej przykładowe zrzuty pokazujące tę technikę w wielu próbkach celujących w różne banki.
Kiedy ofiara zbliża kartę do czytnika, aplikacja przechwytuje dane NFC karty (te same dane, które przepływają przez terminal/bankomat) i wysyła je przez Internet do urządzenia atakującego znajdującego się przy bankomacie ( lub do serwera Command&Control, który następnie wysyła je do urządzenia przy bankomacie). Urządzenie atakującego odtwarza te dane w bankomacie. Dzięki przekazanym danym karty i kodowi PIN atakujący wypłaca gotówkę.
Co znaleźliśmy w analizowanej próbce?
- Aplikacja rejestruje się jako usługa płatnicza HCE (Host Card Emulation) w Androidzie (może zachowywać się jak wirtualna karta).
 - Adres serwera i jego działanie są ukryte w niewielkim zaszyfrowanym pliku dołączonym do aplikacji.
 - Odszyfrowaliśmy ten zasób i wydobyliśmy aktywny serwer c2:
- IP/port: 91.84.97.13:5653
 
 - Interfejs zawiera klawiaturę PIN; PIN jest wysyłany do atakującego razem z danymi NFC.
 
Jak się chronić
- Zawsze pobieraj aplikacje bankowe wyłącznie z oficjalnych sklepów (Google Play Store / App Store).
 - Jeśli dzwoni do Ciebie Twój bank i informuje, iż dzieje się coś złego, rozłącz się i oddzwoń na numer banku. Ta metoda w 100% weryfikuje prawdziwość połączenia.
 
Analiza techniczna
Każda aplikacja na Androida zaczyna się od pliku AndroidManifest.xml. Definiuje on komponenty aplikacji, w tym działania, usługi i uprawnienia. W kontekście analizy kluczową informacją jest ustalenie punktu startowego aplikacji:
Manifest:
- punkt startowy
 
- uprawnienia
 
- usługa HCE
 
- Przykładowa deklaracja AID (skrócona):
 
Wniosek: Aplikacja może zostać skonfigurowana jako usługa płatnicza HCE i będzie wywoływana przez stos NFC podczas komunikacji z terminalem/czytnikiem.
Start procesu
Po zainstalowaniu pliku APK i uruchomieniu procesu (np. po wybudzeniu go przez program uruchamiający/alias lub usługę) strona Java uruchamia natywną bibliotekę pomocniczą, która ładuje i weryfikuje konfigurację środowiska uruchomieniowego. Punktem wejścia do niej jest klasa rha.dev.me.util.Globals.
Podstawowa logika aplikacji jest inicjowana przez System.loadLibrary(„app”);, które ładuje libapp.so do procesu. Ten natywny obiekt odpowiada za najważniejsze etapy: najpierw wyprowadza 32-bajtowy klucz z SHA-256 certyfikatu podpisującego APK (DER). dzięki tego klucza odszyfrowuje on hex blob pobrany z zasobu assets/____ aplikacji. Kolejny krok polega na analizowaniu par tekstowych klucz-wartość z tych odszyfrowanych danych i kompilowaniu ich do wewnętrznej mapy konfiguracyjnej.
Warto zauważyć, iż kod implementuje mechanizm obronny: w przypadku niepowodzenia odszyfrowania lub analizy biblioteka wykonuje wywołanie zwrotne do języka Java w celu wyłączenia programu uruchamiającego - zachowanie to znane jest jako wzorzec safeExit(). Konfiguracja jest uruchamiana przez metodę Java m28b(Context). Metoda ta najpierw wywołuje natywną metodę init(context) w celu skonfigurowania podstawowego stanu współdzielonego, logowania i wewnętrznych zmiennych lokalnych wątku, a następnie wywołuje natywną metodę loadNConfig(context, context.getAssets()) w celu rozpoczęcia procesu odszyfrowywania. W większości kompilacji m28b jest wywoływana bardzo wcześnie - albo z Application.onCreate(), albo z pierwszej Activity.onCreate() - aby zapewnić gotowość niezbędnego gniazda komunikacyjnego w momencie wyświetlenia monitu „zweryfikuj kartę”.
Ponadto natywne flagi boolowskie reader() i vts() ujawniają bity konfiguracyjne (np. reader:=true, mode:=card), umożliwiając warstwie Java dynamiczne określenie, które metody transportu i role NFC należy aktywować.
Natywny moduł ładujący konfigurację (libapp.so) do C2 w postaci zwykłego tekstu
Istotne są dwa elementy natywne: wyprowadzanie klucza i moduł ładujący konfigurację.
Wyprowadzanie klucza (JNI → SHA-256 certyfikatu podpisu):
Zdekompilowana funkcja get_cert_sha(JNIEnv*, unsigned char* out) definiuje proces wyprowadzania klucza. Rozpoczyna się ona wywołaniem funkcji PackageManager.getPackageInfo(..., GET_SIGNATURES). Następnie odczytuje Signature.toByteArray() i opakowuje wynik dzięki CertificateFactory(„X.509”).generateCertificate(InputStream). Następnie wywołuje funkcję cert.getEncoded() i oblicza skrót dzięki MessageDigest(„SHA-256”).digest(encodedCert). Na koniec kopiuje wynikowe 32 bajty do out.
Wniosek: klucz XOR jest dokładnie taki sam jak SHA-256 certyfikatu podpisu aplikacji (DER).
Dekryptowanie i parsowanie konfiguracji
- AAssetManager_open("____", AASSET_MODE_BUFFER) - ładuje ASCII-hex blob z assets/____.
 - hexToBytes() - zamiana na ciphertext binarny.
 - deszyfrowywanie XOR bajt po bajcie przy użyciu 32-bajtowego klucza (powtarzającego się co 32 bajty): c for (i = 0; i < len; i++) pt[i] = ct[i] ^ key[i & 31];
 - Parsuje tekst jawny linia po linii dzięki getline; każda linia musi mieć postać key := value; każda para jest wstawiana do configMap i rejestrowana: c I/AppCheck: Parsed host := 91.84.97.13
 - verifyCnf(env); jeżeli coś się nie powiedzie → wywołaj Java safeExit() (co wyłącza program uruchamiający).
 
Odszyfrowana konfiguracja dla analizowanej próbki::
Reprodukcja offline
Otwarcie połączenia: host/port z JNI, protokół ramkowy
Łączność sieciowa jest zawarta w Transport i C0214a (połączenie i wątki). Uwaga: host/port pochodzą z JNI, tj. odszyfrowanej konfiguracji.
C0214a uruchamia wątek wysyłania i odbierania. To właśnie tam krystalizuje się kształt protokołu.
Wychodzące (client→server): len(4) | opcode(4) | body(len) Przychodzące (server→client): len(4) | body(len) (Kod operacyjny znajduje się wewnątrz ciała jako pole ServerData)
Wybór transportu (TCP vs TLS)
Aplikacja ukrywa tworzenie gniazd za Transport.d(host, port). Istnieją dwie implementacje:
Ramki są łatwe do podpisania na połączeniu, a ponieważ tls=false, payload jest w postaci zwykłego tekstu.
Dyspozytor: rola NetMan i historia opcode
NetMan koordynuje sesję: serializuje komunikaty wyższego poziomu (ServerData) i reaguje na odpowiedzi serwera. Można go traktować jako „mózg sesji”.
Po stronie wejścia blob z serwera jest parsowany do ServerData (natywnie). NetMan obsługuje synchronizację, walidację PIN, listy, kill-switch (ukryj aplikację), a także keepalive co 7 sekund (OP_PING).
Rejestracja NFC: tryb czytnika
Chociaż plik APK zawiera odpowiednią usługę HCE (emulacja karty), odszyfrowana konfiguracja ustawia reader=true, co aktywuje ścieżkę czytnika: telefon zachowuje się jak czytnik prawdziwej karty, którą ofiara przyłożyła do telefonu.
Fragment interfejsu użytkownika wyraźnie pokazuje tę ścieżkę: po rozpoznaniu metadanych karty wyświetla numer PAN, datę ważności i schemat (według AID).
Pod maską parser EMV wypełnia obiekt C0068c (PAN, data ważności, AID). Gdy wszystko jest gotowe, NetMan umieszcza go w CardData i wysyła komunikat OP_CARD_DISCOVERED:
Informacje przesyłane przez sieć są wyraźnie określone w CardData: obejmują numer PAN, identyfikatory AID, datę ważności oraz (później) kod PIN.
Przechwytywanie kodu PIN: z klawiatury do scoketu w jednym kroku
Niestandardowa klawiatura PIN przechwytuje cyfry do specjalnego pola EditText. Po osiągnięciu wymaganej długości (domyślnie 4) publikuje pełny PIN na wewnętrznej szynie zdarzeń.
Warstwa sieciowa nasłuchuje tego zdarzenia i natychmiast eksfiltruje kod PIN jako dedykowany kod opcode:
Serwer odpowiada komunikatem „OP_PIN_VALID” / „OP_PIN_INVALID” (reakcja interfejsu użytkownika), ale w tym momencie kod PIN opuścił już urządzenie. Dodatkowo, podczas serializacji blobu karty (CardData.m87l()), pole PIN może zostać tam również uwzględnione.
Usługa HCE: dowód zdolności „emitera”
Mimo iż ta próbka działa jako czytnik, zawiera w pełni zadeklarowaną usługę HostApduService z identyfikatorem AID podobnym do płatności i bez wymogu odblokowania.
Usługa rejestruje i przekazuje przychodzące komunikaty APDU (jako punkt końcowy przekaźnika), zwracając pustą odpowiedź:
Dlaczego to ma znaczenie? - NGate może pełnić dwie role:: 1. Czytnik wersja, w której ofiara zczytuje swoją kartę, 2. Emiter telefon przy bankomacie (HCE do terminala), połączony tym samym modelem kodu operacyjnego – klasyczna topologia NFC relay.
Summary
NGate to złośliwe oprogramowanie dla systemu Android, które wykorzystuje przekaźnik NFC do wypłacania gotówki z bankomatów przy użyciu kart ofiar. Jest ono dostarczane dzięki phishingu oraz telefonu od „wsparcia bankowego”, który naciska na użytkownika, aby zainstalował aplikację, przyłożył kartę do telefonu i wprowadził PIN. Aplikacja działa w trybie czytnika, aby przechwycić EMV APDU i PIN, a następnie przesyła je dzięki prostego protokołu TCP do zakodowanego na stałe C2; ta sama rodzina dostarcza również usługę HCE kategorii płatności, umożliwiającą pełnienie roli nadajnika w bankomacie. Konfiguracja jest przechowywana jako zasób zaszyfrowany algorytmem XOR z kluczem pochodzącym z certyfikatu podpisującego APK (SHA-256); w tej próbce prowadzi to do jawnego C2. Wniosek: po przyłożeniu karty i wpisaniu PINu napastnik może przekazać sesję i wypłacić gotówkę.
Kluczowe wnioski
- Inżynieria społeczna → aplikacja pobrana z innego źródła → dotknięcie karty + PIN → przekazanie do bankomatu.
 - Obsługiwane role: czytnik (telefon ofiary) i emiter (telefon atakującego/strona bankomatu).
 - Konfiguracja odszyfrowana z zasobów /____ przy użyciu SHA-256(cert) jako klucza XOR.
 - Ramki tekstu jawnego w sieci (len|opcode|body), okresowe sygnały keep-alive.
 - Co opuszcza urządzenie: PAN, data ważności, AID, APDU i PIN.
 

















