Atak DevTap npm Typosquatting

Atak DevTap npm Typosquatting: sześć złośliwych pakietów atakuje stacje robocze programistów

TL; DR

W okresie od 1 kwietnia do 3 maja 2026 r. jeden wydawca npm, user0001, zarejestrowany z niezweryfikowanym adresem Gmail tanvisoul9@gmail.com, po cichu przeforsował sześć pakietów o celowo mdłych, brzmiących jak infrastruktura nazwach: centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime, node-env-resolve.

Dwie najnowsze wersje node-env-resolve, 1.0.7 i 1.0.8 zostały oznaczone przez system wczesnego ostrzegania przed złośliwym oprogramowaniem (MEW) firmy Xygeni 2 maja, a 3 maja potwierdzono ich status jako złośliwy.

Implant jest nietypowy, bo nie jest tym, czym jest: nie ma w nim botów Telegramu, wywołań zwrotnych OAST ani obfuskacjai nie podejmować prób pobrania danych uwierzytelniających AWS podczas instalacji. Zamiast tego, postinstall.js umieszcza wpis dotyczący trwałego rozruchu systemu Windows, używając klucza HKCU Run, który uruchamia wscript.exe do szczątkowego VBS. Następnie tworzy oddzielnego agenta Node.js, który zawiera moduły do ​​przechwytywania mikrofonu, kradzieży historii przeglądania, robienia zrzutów ekranu i symulacji myszy/klawiatury.

Nazywamy to klastrem DevTap, po zainstalowaniu zestawu pozostaje on uruchomiony na komputerze programisty.

Wszystkie sześć pakietów było dostępnych na npm w momencie pisania tego tekstu. Zgłosiliśmy je do kanału zgłaszania nadużyć w rejestrze. Osoby broniące powinny wycofać wszystkie instalacje od wydawcy oczekujące na usunięcie.

Klaster: sześć pakietów, jeden wydawca

Konto wydawcy user0001 jest niezweryfikowany. Nie ma SCM weryfikacja, brak adresów e-mail powiązanych z domeną i brak historii. Adres e-mail w Gmailu tanvisoul9 nie pojawia się w żadnym innym rekordzie wydawcy npm, jaki udało nam się znaleźć.

Wszystkie sześć pakietów ma tego samego opiekuna, zostały opublikowane z tego samego konta i mają ten sam package.json szablon. Nie ma repositoryNie homepage, i nie description dłuższy niż pojedyncza linia.

Strategia nazewnictwa jest interesująca. W przeciwieństwie do klasycznej kampanii polegającej na pomyłce zależności lub typosquatowaniu, żadna z tych nazw nie jest ukierunkowana na konkretną bibliotekę źródłową. Zamiast tego są one skalibrowane tak, aby znikały w rzeczywistym package.json or npm ls wyjście.

PakietOpublikowane po raz pierwszyOstatnia wersjawersjeRola w klastrze
centralogger2026-04-01 12:46 UTC1.0.95, od 1.0.5 do 1.0.9Okładka „narzędzia do rejestrowania” klastra; najwcześniejsze opublikowanie
dom-utils-lite2026-04-14 07:36 UTC1.0.33Ogólna osłona pomocnika DOM
pobieranie-węzła-lite2026-04-19 10:22 UTC1.0.23Naśladuje rodzinę pobierania węzłów
agent łącznikowy2026-04-25 05:12 UTC1.0.01Nazwa ogólna „agent”
node-gyp-runtime2026-04-25 05:17 UTC1.0.01Naśladuje narzędzia do kompilacji natywnych modułów
node-env-resolve2026-04-25 05:21 UTC1.0.910, od 1.0.0 do 1.0.9Aktywny kroplomierz; pełny implant

Nazwy takie jak centralogger, node-fetch-lite, node-gyp-runtime zostały zaprojektowane tak, aby nie budziły kontrowersji podczas przeglądu kodu. Brzmią jak elementy, które już znajdują się w drzewie zależności projektu.

W połączeniu z nowym, niezweryfikowanym wydawcą i brakującymi linkami do repozytorium, tworzą one rozpoznawalny schemat: aktor umieszcza w rejestrze nazwy o niskim współczynniku tarcia, a następnie szybko iteruje po nazwie, która ma znaczenie. W tym przypadku node-env-resolve otrzymałem dziesięć wersji w ciągu ośmiu dni.

Co ląduje na komputerze deweloperskim Windows

Złośliwy łańcuch na node-env-resolve:1.0.8 jest krótki, bezpośredni i niezwykle bogaty w funkcje jak na npm RAT.

Po instalacji: trwałość i odłączony agent

package.json deklaruje pojedynczy hak instalacyjny:

{ "scripts": { "postinstall": "node postinstall.js" } }

postinstall.js wykonuje trzy czynności po kolei.

Najpierw tworzy katalog instalacyjny poza drzewem npm. Ścieżka jest obliczana w czasie wykonywania skryptu jako INSTALL_DIRNastępnie uruchamia wewnętrzny execSync('npm install --production --silent ...') w nim, aby pobrać zależności wykonawcze implantu. To umieszcza agenta na dysku w jakimś miejscu, gdzie można go ręcznie node_modules audyt nie znajdzie.

Po drugie, zapisuje program uruchamiający VBS i rejestruje go w celu utrwalenia rozruchu:

reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \     /v ${AGENT_NAME} \     /t REG_SZ \     /d "wscript.exe \"${vbsPath}\"" /f

wscript.exe jest hostem skryptów systemu Windows, podpisanym plikiem binarnym firmy Microsoft, który uruchamia się .vbs pliki bez okna konsoli. To jest precisDlatego jest to preferowane w przypadku plików szczątkowych typu autorun.

Istnieje również pasujące reg delete ścieżka wewnątrz src/index.jsco sugeruje, że implant został zaprojektowany tak, aby można go było łatwo usunąć na polecenie operatora.

Po trzecie, tworzy oddzielny proces potomny:

spawn(node, [path.join(INSTALL_DIR, 'src/index.js')], {   detached: true,   env: { ...process.env, SERVER_URL } })

W tym przypadku istotne są dwa szczegóły.

SERVER_URL jest odczytywany ze środowiska. W rezultacie punkt końcowy C2 jest konfigurowalny dla każdego wdrożenia i nie jest wbudowany w pakiet. Ten drobny, ale przemyślany wybór niweczy większość analiz statycznych IOC.

Ponadto, utworzone dziecko dziedziczy pełne środowisko nadrzędne. Dlatego każde NPM_TOKEN, AWS_*, GITHUB_TOKENlub gniazdo agenta SSH obecne w powłoce deweloperskiej w momencie instalacji trafia do pamięci długotrwałego agenta.

Co agent wysyła

Pakiet src/ Drzewo składa się z trzech modułów, których nazwy same w sobie opowiadają historię: audioCapture.js, browserHistory.js, systemInfo.js.

Lista zależności czasu wykonania, rozwiązana podczas etapu przygotowawczego npm install, potwierdza je.

Podejście to zmienia chaotyczny incydent w kontrolowaną reakcję.

Zamiast reagować ślepo, zespoły działają w oparciu o jasne ustalenie priorytetów i szybkie rozwiązanie.

ZależnośćDo czego służy w tym kontekście
zrzut ekranu pulpituOkresowe przechwytywanie ekranu
@nut-tree-fork/nut-jsAutomatyzacja myszy i klawiatury / symulacja wprowadzania danych
lepszy sqlite3Bezpośrednie odczyty baz danych SQLite z historii przeglądarek Chrome, Edge i Firefox
adm-zipPakowanie zebranych artefaktów przed eksfiltracją
ostryZmiana rozmiaru/kompresja zrzutów ekranu i artefaktów obrazu
socket.io-clientTrwały dwukierunkowy kanał C2
identyfikator maszyny-węzłaStabilny odcisk palca dla każdego hosta umożliwiający śledzenie ofiar

systemInfo.js Połączenia os.networkInterfaces() w celu przeprowadzenia dodatkowego pobierania odcisków palców przed pierwszym sygnałem.

Dlaczego przechwytywanie dźwięku jest sygnałem wyróżniającym się

Większość npm RAT-ów, które testujemy w MEW, zatrzymuje się na kradzieży sekretu w czasie instalacji. ~/.npmrc, przeczytaj ~/.aws/credentials, skrobać process.env, POST do webhooka i wyjście. To pasuje do modelu ekonomicznego typu „rozbij i chwyć”. Dane uwierzytelniające mają krótki okres półtrwania, a atakujący musi szybko je spieniężyć.

node-env-resolve ma inny kształt.

Trwałość jest skonfigurowana tak, aby przetrwać ponowne uruchomienie. Agent działa niezależnie i długotrwale. wscript.exeZestaw, który zawiera, jest przeznaczony do umieszczenia na komputerze programisty, a nie do zabrania i wyrzucenia: rejestrator mikrofonu, sterownik klawiatury/myszy, pełne pobieranie historii przeglądarki, przechwytywanie ekranu i interaktywny kanał Socket.IO z powrotem do konfigurowalnego C2.

W szczególności przechwytywanie mikrofonu to granica, którą ta kampania przekracza, a większość złośliwego oprogramowania npm nie.

Stanowisko programisty to coraz częściej również miejsce, w którym programiści prowadzą stand-upy, rozmowy z klientami, dyskusje projektowe i rozmowy na telefon. Implant, który nagrywa dźwięk z mikrofonu, nie jest tak naprawdę potrzebny tokenowi npm programisty. Chodzi o to, co programista mówi przed laptopem.

Taki zestaw możliwości, a także brak maskowania i braku efektownego wykradania danych podczas instalacji, sprawia wrażenie przygotowania do ukierunkowanego dostępu, a nie oportunistycznej kradzieży danych uwierzytelniających.

Nie opieramy się wyłącznie na tym stwierdzeniu. Odnotowujemy profil operacyjny.

Atak npm typosquatting - DevTab

Ośmiodniowa iteracja rytmiczna node-env-resolve jest najbardziej znaczącym szczegółem operacyjnym na osi czasu.

To nie jest drop typu „wystrzel i zapomnij”. Wydawca aktywnie utrzymuje dropper, co zazwyczaj oznacza jedną z dwóch rzeczy. Albo dostraja go do środowisk testowych przed szerszym wdrożeniem, albo już otrzymuje dane telemetryczne z instalacji i na nie reaguje.

Pozostałe pięć pakietów praktycznie nie odnotowało odejścia od platformy po ich pierwszej publikacji. To pasuje do schematu „etap raz, zostaw nazwę” dla klastra pomocniczego, podczas gdy wysiłki inżynieryjne koncentrują się na pakiecie, który wykonuje pracę.

Atrybucja: drobne wskazówki, brak jednoznacznego werdyktu

Publiczne OSINT Sygnały są słabe i nie będziemy ich rozciągać. Co można zaobserwować:

Uchwyt Gmaila tanvisoul9 częściowo przypomina imię południowoazjatyckie „Tanvi”. To słaby sygnał. Konta w Gmailu nie są tożsamością, a końcowy soul9 jest ogólny. Nie jest bezpieczne wnioskowanie o geografii na podstawie samej lokalnej części wiadomości e-mail.

Styl kodu Node.js jest nieciekawy: standard wywołania biblioteczne takie jak os, child_process, spawn, reg addBrakuje zaciemniania, rotacji ciągów znaków ani logiki antydebugowej. Autor dobrze radzi sobie z prymitywami rejestru systemu Windows i orkiestracją odłączonych procesów potomnych, ale nie wydaje się, by sięgał po bardziej dyskretne sztuczki, z których mógłby korzystać.

Zależności są całkowicie gotowe i dobrze znane: screenshot-desktop, nut-js, better-sqlite3, socket.io-clientNie ma żadnego niestandardowego protokołu, żadnego stosu C2 stworzonego od podstaw ani żadnej nowej sztuczki trwałości poza podręcznikiem Klucz HKCU RunTo jest kompetentny integrator, a nie autor narzędzi.

W opublikowanych artefaktach nie znaleźliśmy ciągów znaków w języku innym niż angielski, osadzonych komentarzy, danych dotyczących ustawień regionalnych ani odcisków palców stref czasowych kompilatora.

Sprawdziliśmy, czy kod nie pokrywa się z poprzednimi kampaniami, które już śledzimy, w tym Shai Hulud, Owlivion, Buildkite i niedawny heibai / claude-code-best Rodzina klonów Anthropic-CLI. Nie znaleźliśmy żadnych: żadnych wspólnych wzorców C2, żadnych wspólnych układów plików ani żadnych wspólnych idiomów.

Czego nie powiedzielibyśmy: że jest to podmiot państwowy, znana grupa lub że jest ona powiązana geograficznie z jakimś konkretnym krajem.

Profil operacyjny jest spójny z małym, średnio wykwalifikowanym zespołem zajmującym się nadzorem stacji roboczych programistów. Prawdopodobnie jest to motywowane finansowo poprzez dalsze wykorzystanie dostępu, ale możliwe jest również świadczenie usług rozpoznania dla oddzielnego nabywcy.

Dwa pośrednie argumenty przemawiają za tym, że należy unikać mechanizmów eksfiltracji przyciągających uwagę, które szybko spaliłyby klaster, takich jak boty Telegramu, oastify.comlub canarytokens, a także celowo nijakie nazwy pakietów, które faworyzują ciche instalacje z długim ogonem zamiast krótkotrwałych skoków głośności.

Wskaźniki naruszenia i wykrycia

Pakiety i wydawca
PoleWartość:
wydawca npmuser0001
Adres e-mail wydawcytanvisoul9@gmail.com, niezweryfikowany
Pakietycentralogger, dom-utils-lite, node-fetch-lite, agent łącznika, node-gyp-runtime, node-env-resolve
Potwierdzono złośliwośćnode-env-resolve@1.0.7, node-env-resolve@1.0.8
Artefakty gospodarza
TypWartość:
Klucz trwałościHKCU\Software\Microsoft\Windows\CurrentVersion\Run
Wartość trwałościNazwa zmiennej; dane w formacie wscript.exe " \\ .vbs"
Zainstaluj hakpostinstall: węzeł postinstall.js w manifeście pakietu
Moduły implantówsrc/audioCapture.js, src/browserHistory.js, src/systemInfo.js
Katalog przejściowyINSTALL_DIR został rozwiązany i znajduje się poza node_modules projektu; lokalizacja ustawiona przez postinstall.js w czasie instalacji
Sieć
TypWartość:
Transport C2socket.io-client, trwały kanał dwukierunkowy
Punkt końcowy C2Dostarczone agentowi za pośrednictwem zmiennej środowiskowej SERVER_URL; nie jest zakodowane na stałe w opublikowanych artefaktach

Notatki dotyczące wykrywania

Dwie reguły obejmują tę rodzinę bez potrzeby stosowania punktu końcowego C2.

Najpierw oznacz skrypty poinstalacyjne, które wykonują wewnętrzną operację npm install do ścieżki poza katalogiem pakietu. Każdy legalny program do pobierania gotowych pakietów, taki jak node-gyp odbudowuje lub wstępnie kompiluje programy do pobierania plików binarnych, zapisuje wewnątrz pakietu lub na platformiestandard ścieżki pamięci podręcznej ze zweryfikowanymi haszami. Nie zapisuje do nowo utworzonego INSTALL_DIR w innym miejscu na dysku.

Po drugie, oznacz flagą skrypty poinstalacyjne, które wydają polecenie reg add HKCU\…\Run w wscript.exe jako program uruchamiający. Zasadniczo nigdy nie jest to legalne w przypadku pakietu npm. Należy go oznaczyć flagą i umieścić w kwarantannie.

Trzecia heurystyka jest przydatna do wykrywania kolejnego pakietu siostrzanego przed jego potwierdzeniem: nowy wydawca npm bez SCM weryfikacja, e-mail Gmail, nie repository pole i wiele krótkich, ogólnych nazw pakietów przypominających nazwy infrastruktury opublikowanych w odstępie kilku dni to już samo w sobie wystarczający powód, aby uzasadnić ręczną recenzję.

Zgłoszono do rejestru npm. Zaktualizujemy ten wpis, gdy konto wydawcy zostanie usunięte.

sca-tools-oprogramowanie-narzędzia-analizy-kompozycji
Określ priorytety, rozwiąż problemy i zabezpiecz zagrożenia związane z oprogramowaniem
Załóż darmowe konto.
Nie wymagamy karty kredytowej.

Zabezpiecz swoje oprogramowanie i dostarczanie

z pakietem produktów Xygeni