Mega Sekurak Hacking Party w Krakowie! 26-27.10.2026 r.

Jak sprytnie ukryć malware czyli kampania z PhantomRaven

06 listopada 2025, 01:09 | W biegu | 0 komentarzy

W październiku skaner Wings (od Koi) wykrył wiele paczek npm, które wysyłały podczas instalacji żądania do zewnętrznych zasobów – wszystkie do tej samej domeny. W trakcie analizy badacze odkryli kampanię, która trwała nieprzerwanie od sierpnia 2025.

TLDR:

– Badacze wykryli aktywną od sierpnia 2025 kampanię malware PhantomRaven.

– Złośliwy kod był dostarczany jako zdalna zależność, omijając standardowe skanery bezpieczeństwa.

– Malware wykradało dane uwierzytelniające programistów i tokeny CI/CD oraz poświadczenia do npm.

– Atak wykorzystywał halucynacje LLM (np. ChatGPT) przez technikę slopsquatting – tworzenie paczek o mylących nazwach.

Zasięg był duży. Kampania objęła łącznie 126 paczek (zarówno tworzonych przez atakujących oraz istniejących – przejmowanych przez nich – pakietów). W chwili wykrycia 80 z nich było wciąż aktywnie wykorzystywanych – nadal wykradały dane uwierzytelniające. To malware otrzymało przydomek PhantomRaven.

Do tworzenia paczek wykorzystywane były kolejne konta e-mail od darmowych dostawców – jpdtester01@hotmail[.]com, jpdtester02@outlook[.]com, aż do jpdtester13@gmail[.]com. Korzystano także z nazw użytkowników takich jak npmhell lub npmpackagejpd. Można było więc łatwo je wykryć i powiązać ze sobą, ale atakującemu nie chodziło o same paczki.

Sam mechanizm dostarczania złośliwego kodu był tutaj kluczowy i całkiem sprytny. Nie umieszczano go w zainfekowanych paczkach, tylko jako zdalne zależności.

Wynika to z faktu, że dla każdej paczki można wskazać dodatkowe pakiety, które są wymagane do jej działania. Można zdefiniować je po wersji (z oficjalnego repozytorium npm) lub podać adres URL, pod którym można pobrać daną paczkę. I to właśnie z tej drugiej opcji skorzystano do dystrybucji złośliwego kodu. Atakujący może więc do zupełnie nieszkodliwej paczki przypisać dowolną dodatkową zależność.

Przykład definiowania dodatkowych zależności dla paczki

Co ważne, żadne potencjalnie niebezpieczne czy podejrzane operacje nie były wykonywane z poziomu kodu złośliwej paczki. Dodawane było jedynie odwołanie do zdalnego pakietu – dopiero on zawierał złośliwy kod.

Kiedy użytkownik instaluje pakiet z tego typu zależnością, npm pobiera ją ze wskazanego zewnętrznego adresu URL. Nie z oficjalnego repozytorium npm tylko z dowolnego miejsca, które zdefiniuje atakujący.

A npm nie analizuje kodu zdalnych paczek. Wbudowane w npm narzędzia do analizy zależności domyślnie ich nie sprawdzają. 

Przykładowa paczka z dodatkowym pakietem, źródło: www.koi.ai

Za każdym razem, gdy użytkownik uruchamia komendę npm install, ta zależność jest pobierana z zewnętrznego serwera (w tym przypadku wskazanego przez atakującego). Nie jest przechowywana w pamięci podręcznej, więc każde użycie komendy powoduje pobranie aktualnej wersji z serwera.

Atakujący może skonfigurować adres wymaganej zależności w taki sposób aby wskazywał na rejestr znajdujący się pod jego kontrolą. To daje możliwość przeprowadzenia ataku na łańcuch dostaw i dokładną kontrolę tego, jaki kod jest pobierany i uruchamiany przez użytkownika końcowego. 

Daje to potencjalnie możliwość przeprowadzania celowanych ataków. Zawartość może być różna w zależności od adresu IP – złośliwy kod dla sieci korporacyjnych, specjalna wersja dla środowisk chmurowych i nieszkodliwa np. w miejscach, gdzie atakujący nie spodziewa się konkretnej ofiary, a zwiększyłoby się ryzyko wykrycia ataku.

Albo, dla uśpienia czujności, przez jakiś czas dostarczać nieszkodliwy kod, przejść ewentualne dodatkowe skany bezpieczeństwa, a następnie zacząć serwować złośliwą wersję.

Po uruchomieniu polecenia npm install nie tylko pobierane są pakiety, ale również są wykonywane skrypty instalacyjne. A ściślej: uruchamiane są pliki zdefiniowane w package.json – preinstall, install i postinstall.

Skrypt preinstalacyjny uruchamia się automatycznie, bez potwierdzenia czy ostrzeżenia. Nie wymaga interakcji ze strony użytkownika.

Kompletny schemat ataku wygląda więc tak:

  1. Deweloper instaluje paczkę, która nie wzbudza podejrzeń, z repozytorium npm
  2. npm pobiera dodatkowy pakiet z serwera atakującego wraz z zawartym w nim skryptem preinstalacyjnym
  3. npm automatycznie uruchamia plik node index.js (pobrany z serwera atakującego razem z pakietem)
  4. Złośliwe oprogramowanie zostaje uruchomione

Wszystko to dzieje się w ciągu kilku sekund potrzebnych na ukończenie instalacji npm.

Na początku malware przeszukuje całe środowisko w poszukiwaniu adresów e-mail – sprawdza zmienne środowiskowe, plik .gitconfig, .npmrc, a także pole autora w pliku package.json. Następnie szuka konfiguracji środowiska CI/CD – pozyskuje tokeny GitHub Actions, dane uwierzytelniające GitLab CI, Jenkins, CircleCI. 

Wykradanie poświadczeń użytkownika, źródło: www.koi.ai

Dodatkowo wyszukuje tokeny uwierzytelniające do npm, dzięki czemu zyskuje możliwość publikowania złośliwych aktualizacji dowolnego pakietu, którym zarządza użytkownik.

Pobierany jest także publiczny adres IP użytkownika, nazwa hosta, szczegóły systemu operacyjnego, lokalny adres IP, nazwa użytkownika, bieżący katalog i wersja Node.js.

I na koniec eksfiltracja – najpierw żądanie GET z wszystkimi danymi zakodowanymi w adresie URL. Następnie żądanie POST z tymi samymi danymi w formacie JSON. Jeśli oba zawiodą? Nawiązywane jest połączenie WebSocket z zapasowym serwerem.

Nazwy pakietów wykorzystywanych w ramach PhantomRaven nie są przypadkowymi literówkami. Zostały starannie dobrane, aby wykorzystać ciekawą właściwość dużych modeli językowych – halucynacje. Mowa o ataku typu slopsquatting.

Kiedy programiści generują kod przy pomocy LLM, modele te czasami generują wiarygodnie brzmiące nazwy paczek, które w rzeczywistości nie istnieją. Atakujący wykorzystali te nieistniejące nazwy.

Przykładowe nazwy paczek:

  • eslint-comments – prawdziwa: eslint-plugin-eslint-comments
  • transform-react-remove-prop-types – prawdziwa: babel-plugin-transform-react-remove-prop-types
  • unused-imports – prawdziwa: eslint-plugin-unused-imports

Programista, ufając rekomendacji AI, instaluje je bez zastanowienia. Paczka może być nawet dostępna w oficjalnym repozytorium npm, bo przecież sama w sobie nie zawiera żadnego złośliwego kodu.

Malware PhantomRaven pokazuje jak atakujący wykorzystują słabe punkty różnych narzędzi. Zdalne zależności nie są widoczne w interfejsie npmjs[.]com i nie podlegają skanom bezpieczeństwa w ramach oficjalnego repozytorium. Programiści powinni być wyczuleni na fakt, że nie wszystkie odpowiedzi wygenerowane przez LLMy są prawdziwe, a każdy wygenerowany kod powinien zostać manualnie zweryfikowany. Niby oczywistość, ale mamy wrażenie, że rozsądek i dobre praktyki swoje – a życie swoje.

Źródło: www.koi.ai

~Tymoteusz Jóźwiak

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

Odpowiedz