TL; DR
Dwadzieścia pakietów npm opublikowanych w ciągu dwóch dni pod koniec lipca i na początku sierpnia 2026 roku prezentuje się jako wewnętrzne biblioteki komponentów interfejsu użytkownika i współdzielone narzędzia zaplecza. Żaden z nich nie implementuje reklamowanej funkcjonalności. Każdy z nich zawiera klasę szczątkową, plik README opisujący pakiet jako wewnętrzny oraz plik o nazwie _polyfill.js.
Ciekawą częścią jest to, skąd ten plik jest wywoływany. To nie jest hak instalacyjny — w manifestach nie ma w ogóle żadnych deklaracji preinstall, install ani postinstall. Zamiast tego ostatni wiersz index.js czytamy: try { require("./_polyfill"); } catch (_) {}Ładunek uruchamia się, gdy kod aplikacji po raz pierwszy importuje pakiet. Instalacja za pomocą --ignore-scriptsThe standard porady dotyczące ograniczania narażenia łańcucha dostaw w czasie instalacji, nie zapobiega temu.
Co _polyfill.js Pobiera plik wykonywalny specyficzny dla platformy z jednego z trzech hostów Cloudflare Workers, zapisuje go do katalogu tymczasowego pod losową nazwą, oznacza jako wykonywalny i uruchamia w odłączeniu od procesu nadrzędnego. Ten plik wykonywalny sam w sobie jest programem ładującym: wylicza produkty bezpieczeństwa punktów końcowych według nazwy procesu, sprawdza bieżącą nazwę użytkownika w odniesieniu do znanych kont w środowisku analizy, aktualizuje interfejsy telemetryczne AMSI i ETW w pamięci, instaluje trwałość pod nazwą komponentu audio systemu Windows i pobiera trzeci plik binarny o rozmiarze kilku megabajtów. Trzeci etap jest dostarczany w postaci zaszyfrowanej i jest… odszyfrowane i wykonane w pamięci, a nie zapisane na dysku.
1 sierpnia, około cztery godziny po potwierdzeniu złośliwego charakteru pakietów podczas ręcznej weryfikacji, dziewiętnaście z dwudziestu nazw zostało usuniętych z npm przez ich własnego wydawcę w ciągu dwudziestu pięciu sekund. 2 sierpnia jedna z tych nazw została zarejestrowana ponownie – przez inne konto, z tym samym kodem. W momencie pisania tego tekstu infrastruktura dostaw obsługiwała wszystkie trzy etapy.
| Pakiety | 20 nazw npm, ~74 opublikowane wersje |
| Nazewnictwo tematów | beaver-ui-* (13) accounts-* (3), a także afisha-storybook-default, bcore-bravo-eslint-config, arbocrate-sla-prober-arbocrate-sla-prober-core, a.poltoradnev-package-c |
| Cyngiel | Import modułu (require), nie jest to skrypt cyklu życia npm |
| Etap 1 | _polyfill.js — pobieranie i uruchamianie |
| Etap 2 | Statycznie powiązany program ładujący, spakowany za pomocą UPX w systemie Linux; wyliczanie zabezpieczeń punktów końcowych, łatanie AMSI/ETW, trwałość |
| Etap 3 | beacon_linux.bin / beacon_mac.bin / update_win.exe, 4–13 MB; dostarczane w postaci zaszyfrowanej, wykonywane w pamięci |
| Buty na platformie | Linux x64 i arm64, macOS uniwersalny, Windows x64 |
| Wydawcy | Dwa konta, jedna baza kodu |
| Status | 19 z 20 nazwisk nieopublikowanych przez operatora; 1 ponownie opublikowane i uruchomione; infrastruktura dostaw na żywo |
Anatomia ataku
Etap 1 — pakiet
Każdy członek wysyła pilniki o takim samym kształcie. indeks.js eksportuje klasę z w tym() który ustawia wartość logiczną, a wersja()I konfiguruj() który scala obiekt opcji. Nic więcej. README.md podaje linię instalacyjną, wymagać wiersz i zdanie „Pakiet wewnętrzny. Zobacz CONTRIBUTING.md, aby uzyskać wytyczne” — WSPÓŁPRACA.md nie ma go w archiwum.
_polyfill.js Ma nieco mniej niż 5 KB i czyta się jak zwykły kod infrastruktury. Otwiera się trzema sprawdzeniami środowiska:
if (process.env.DISABLE_TELEMETRY ||
process.env.ANALYTICS_OPT_OUT ||
process.env.DO_NOT_TRACK)
return; Te zmienne to konwencjonalne mechanizmy kontroli prywatności. W tym przypadku decydują one, czy plik binarny zostanie pobrany i wykonany. Maszyna, która ustawia NIE_ŚLEDŹ jest całkowicie pomijany.
Następnie następuje jednorazowy stempel: plik w /tmp/.analytics_statelub stan_analityczny dla % Temp% w systemie Windows, którego czas modyfikacji jest porównywany z oknem 20 357 sekund. W tym oknie moduł powraca natychmiast, więc wielokrotne importy podczas kompilacji powodują jedną próbę pobrania zamiast kilkudziesięciu.
Hosty docelowe nie występują jako literały. Są one tworzone w czasie wykonywania z fragmentów:
["oob-worker.cf102-","baf.workers.d","ev"].join("") W ten sposób budowane są trzy hosty, które przed użyciem są tasowane, więc kolejność zmienia się w zależności od wykonania. Pobieranie to żądanie HTTPS GET przypięte do IPv4 z User-Agent of pobieranie-węzła/2.6 — prawdopodobna wartość do wyemitowania przez proces węzła. Odpowiedź poniżej 1,000 bajtów jest odrzucana, a następnie próbowany jest kolejny host.
Jeśli wszystkie trzy zawiodą, moduł powraca do DNS. Wysyła zapytanie TXT o C. aby uzyskać liczbę fragmentów, a następnie żąda 0. przez N. W partiach po dziesięć, łączy odpowiedzi i dekoduje wynik algorytmem Base64. Ta ścieżka przenosi ten sam plik wykonywalny przez rekordy DNS TXT, który przetrwa środowiska, w których wychodzące połączenia HTTP są filtrowane, ale rozpoznawanie nazw DNS nie.
Pobrane bajty są zapisywane do /var/tmp/.cache_<8-heks> na Unixie lub %TEMP%\dotnet_diag_<8-hex>.exe W systemie Windows — nazwa pliku, która jest artefaktem diagnostycznym .NET. W systemie Unix plikowi przypisano tryb 0755. Uruchomienie to ikra w oderwany: prawda, stdio: „ignoruj”, unref(), więc dziecko przeżywa proces Node, który je uruchomił; w systemie Windows wywołanie dodaje windowsHide: prawda.
Obraz dopełniają dwa szczegóły. Pomocnik zdefiniowany jako const _l = (…a) => process.stderr.write(“”) jest wywoływana na każdym etapie pobierania — zapisuje pusty ciąg i odrzuca jego argumenty, zajmując miejsce, w którym znajdowałby się rejestr. Każdy pakiet zawiera plik o rozmiarze 81 KB. lib/telemetry.js którego komentarz w nagłówku opisuje „zestaw SDK do analizy danych” z „transportem HTTPS z rotacją i ponawianiem punktów końcowych” oraz „wykrywaniem usług opartych na DNS w celu przełączania awaryjnego”. W obecnej kompilacji nic tego nie wymaga.
Etap 2 — ładowarka
Plik binarny dla Linuksa x64 to statycznie linkowany plik ELF skompresowany za pomocą UPX 3.96. Kompilacja dla macOS to uniwersalny plik binarny obejmujący x86_64 i arm64; kompilacja dla Windows to uproszczony plik wykonywalny konsoli PE32+. Wszystkie cztery pliki zostały pobrane i przeanalizowane statycznie; żaden nie został uruchomiony.
Importy i tabela ciągów w kompilacji systemu Windows jasno opisują jego zachowanie. Rozwiązuje to Czy Debugger jest obecny, SprawdźObecnośćZdalnegoDebuggera, Proces informacyjny NtQueryi czyta SYSTEM\CurrentControlSet\Usługi\Dysk\Enum — ścieżka rejestru, której wartości identyfikują wirtualne kontrolery dysków. Wywołuje GetDiskFreeSpaceExW oraz Globalny Status PamięciEx, co jest zgodne ze sprawdzaniem, czy zasoby hosta odpowiadają krótkotrwałemu wystąpieniu analizy.
Zawiera listę nazw użytkowników: Aktualny użytkownik, Administrator IT, Hong Lee, TESTBOX, hapubws, milozs, Timmy, Admin, malware, próba, wirus, środowisko. Kilka z nich to artefakty publicznie udokumentowanych środowisk analitycznych.
Zawiera również listę produktów zabezpieczających punkty końcowe i nazwy ich procesów, wyszczególnione za pomocą UtwórzToolhelp32Snapshot oraz Proces32FirstW/Proces32NastępnyW:
- Sokół CrowdStrike (
csfalconservice,CSFalconContainer) - Carbon Black (
cb.exe) - Cylance (
cylancesvc.exe) - Bitdefender (
bdagent.exe) - Kaspersky (
avp.exe,kavfs.exe) - Trend Micro i Deep Security (
coreServiceShell,ds_agent.exe) - FireEye/Trellix (
xagt.exe) - Tanium (
taniumclient.exe) - HitmanPro (
hmpalert.exe) - Elastyczna (
elastic-agent.exe,elastic-endpoint,filebeat.exe,winlogbeat.exe) - Wazuh i OSSEC (
wazuh-agent.exe,ossec-agent.exe) - Check Point
- Windows Defender
Obecne są jeszcze dwa symbole: Bufor AmsiScanpunkt wejścia udostępniany przez system Windows do skanowania zawartości w pamięci oraz Zapis zdarzenia Etw, funkcja, za pomocą której Event Tracing for Windows rejestruje zdarzenia. Obie są częstymi celami modyfikacji w trakcie procesu, które tłumią dane telemetryczne generowane przez te interfejsy.
Trwałość pojawia się dwukrotnie w systemie Windows. Plik binarny jest kopiowany do %APPDATA%\Microsoft\Windows\Themes\SystemSoundsService.exei odwołują się do niego dwa mechanizmy: wartość poniżej OPROGRAMOWANIE\Microsoft\Windows\Bieżąca wersja\Uruchomi zaplanowane zadanie zarejestrowane jako
schtasks /Create /F /SC ONLOGON
/TN "\Microsoft\Windows\Multimedia\SystemSoundsService"
/TR "\"%s\""
/RL HIGHEST Ścieżka zadania, nazwa zadania i nazwa pliku wykonywalnego odzwierciedlają oryginalny komponent audio systemu Windows. /RL NAJWYŻSZY żąda najwyższego dostępnego poziomu uprawnień.
Kompilacja systemu macOS postępuje według tego samego schematu, stosując nazwy odpowiednie dla platformy: zapisuje listę właściwości ~/Library/LaunchAgents/com.apple.windowserver.helper.plist i umieszcza swój plik wykonywalny w ~/.local/share/runtime/com.apple.runtime. Sprawdza się /Aplikacje/VMware Fusion.app oraz /Biblioteka/Wsparcie aplikacji/Narzędzia VMware.
Możliwości sieci obejmują trzy transporty: WININET.dll dla HTTPS z https://%s:%d%s ciąg formatujący, WS2_32.dll gniazdka i DNSAPI.dll w DNSQuery_A obok a c.%s.%s ciąg formatujący — taki sam kształt zapytania o liczbę fragmentów, jaki jest używany w pierwszym etapie.
Powyższy opis przedstawia importy, ciągi znaków i ścieżki rejestru pliku binarnego widoczne po inspekcji. Publiczna analiza wielosilnikowa tej samej próbki systemu Windows dodaje szczegóły, których statyczny odczyt tabeli importów nie jest w stanie ustalić samodzielnie, i jest tu przypisana, a nie powtórzona jako obserwacja z pierwszej ręki. Analiza ta donosi, że odwołania do AMSI i ETW zostały nie tylko rozwiązane, ale także poprawione — Bufor AmsiScan in amsi.dll oraz Zapis zdarzenia Etw in ntdll.dll — która blokuje skanowanie zawartości w pamięci i śledzenie zdarzeń dla procesu. Raportuje kontrole antyanalizy jako oparte na czasie, a także SprawdźObecnośćZdalnegoDebuggerai identyfikuje Pobierz kontekst wątku Wywołanie jako sprawdzenie punktu przerwania sprzętu poprzez odczyt rejestrów debugowania. Zgłasza również pojedynczy mutex, Global\{7A3B9E1F-C2D4-4F8A-B5E6-D7A1F0C3E2B9}i imiona Usługa dźwięków systemowych jako wartość klucza Run. Ta wartość mutexa nie znalazła się wśród odzyskanych tutaj ciągów znaków – użyty filtr ekstrakcji wykluczył tokeny szesnastkowe z wielkimi literami – i została zapisana w tabeli wskaźników na podstawie tej publicznej analizy, a nie bezpośredniej obserwacji.
Etap 3
Program ładujący odwołuje się do kolejnego zestawu ścieżek na tych samych hostach. Wszystkie były dostępne podczas analizy: beacon_linux.bin przy 5.3 MB, beacon_mac.bin przy 13.3 MB, update_win.exe przy 10.3 MB i ramię.bin o rozmiarze 4.3 MB. Nie zostały one pobrane i ich zachowanie jest nieznane.
W przypadku ścieżki systemu Windows publiczna analiza modułu ładującego opisuje sposób obsługi trzeciego etapu: jest on pobierany przez sieć WinINet, dociera w postaci zaszyfrowanej, odszyfrowywany w pamięci i wykonywany refleksyjnie — pamięć jest przydzielana, importy są rozwiązywane, relokacje są przetwarzane, a sterowanie przekazywane do nowego wątku za pośrednictwem Utwórz wątekZ tego powodu trzeci etap nigdy nie jest zapisywany w systemie plików, więc wykrywanie oparte na plikach i analiza kryminalistyczna dysków po incydencie nie dają możliwości odzyskania danych. Oznacza to również, że pobranie bajtów od hosta dostarczającego dałoby tekst zaszyfrowany, a nie plik wykonywalny nadający się do analizy.
Oś czasu
Wszystkie znaczniki czasu są podane w strefie UTC i pochodzą z metadanych rejestru npm, w którym niezależnie od obserwatora rejestrowane są utworzenia i niepublikowanie pakietów.
| Kiedy | Co |
|---|---|
| 2026-07-31 09:25:05 → 09:29:56 | Utworzono dziesięć nazw, każda zaczynająca się od wersji 0.0.1, w odstępie około trzynastu sekund. |
| 2026-08-01 09:38 → 11:29 | Istniejące nazwy pną się w górę przez zawyżone numery wersji, 6.1.9 przez 6.1.12, 9.9.9 przez 9.9.12, 8.9.3 przez 8.9.6, 5.4.6 przez 5.4.9. |
| 2026-08-01 13:04:14 → 13:04:18 | Dziewięć dalszych beaver-ui-* nazwy utworzone w ciągu czterech sekund, każda opublikowana bezpośrednio w wersji 12.x, bez żadnej wcześniejszej historii. |
| 2026-08-01 ~13:00–14:30 | Wersje sklasyfikowane jako złośliwe po ręcznym przeglądzie. |
| 2026-08-01 17:39:49 → 17:40:14 | Dziewiętnaście z dwudziestu nazwisk nieopublikowanych w ciągu dwudziestu pięciu sekund, jedna po drugiej, w odstępie około 1.2 sekundy. |
| 2026-08-02 18:58:41 | a.poltoradnev-package-c ponownie utworzony na innym koncie opiekuna, wersja 0.0.2. |
| 2026-08-02 19:20:28 | Wersja 33.9.5 opublikowane pod tą samą nazwą. |
| 2026-08-02 20:14 | Wszyscy trzej hostowie dostarczający obsługują etapy drugi i trzeci; rezerwowe odpowiedzi DNS z liczbą fragmentów. |
Warto zatrzymać się nad dwoma spośród tych wpisów.
W ciągu czterech sekund seria 13:04 umieściła w rejestrze dziewięć pakietów, każdy z jedną wersją w dwunastu i żadnym 0.0.1 poniżej. Numery wersji na tej skali, dotyczące nazw sprzed jednego dnia, nie opisują historii wydań.
Sekwencja usuwania wpisów z publikacji jest równie mechaniczna: dziewiętnaście nazw, dwadzieścia pięć sekund, równe odstępy. npm rejestruje je jako zwykłe zdarzenia usuwania wpisów z publikacji, a nie jako symbol zastępczy pozostawiony po usunięciu zainicjowanym przez rejestr, który przypisuje działanie do konta publikującego, a nie do rejestru.
Wskaźniki kompromisu
Hosty i ścieżki są odszyfrowane. Nie należy ich rozwiązywać ani pobierać z systemu produkcyjnego.
| Typ | Wartość: |
|---|---|
| Dostawca usług hostingowych | oob-worker[.]cf99-9b3[.]workers[.]dev |
| Dostawca usług hostingowych | oob-worker[.]cf102-baf[.]workers[.]dev |
| Dostawca usług hostingowych | oob-worker[.]cf103-070[.]workers[.]dev |
| Transport DNS | tin[.]dl[.]well1[.]site (Linux x64), tina[.] (arm64), ldr[.] (System operacyjny Mac), win[.] (Windows) — liczba fragmentów w c.<domain>, dane w <n>.<domain> |
| Ścieżki etapu 2 | /pkg/package, /pkg/package-arm64, /pkg/loader_mac, /pkg/package.exe |
| Ścieżki etapu 3 | /pkg/beacon_linux.bin, /pkg/beacon_mac.bin, /pkg/update_win.exe, /pkg/arm.bin |
| Ścieżka upuszczania (Unix) | /var/tmp/.cache_<8-hex> |
| Ścieżka upuszczania (Windows) | %TEMP%\dotnet_diag_<8-hex>.exe |
| Trwałość (Windows) | %APPDATA%\Microsoft\Windows\Themes\SystemSoundsService.exe; zadanie \Microsoft\Windows\Multimedia\SystemSoundsService; Wartość klucza uruchomieniowego SOFTWARE\Microsoft\Windows\CurrentVersion\Run\SystemSoundsService |
| Mutex (Windows) | Global\{7A3B9E1F-C2D4-4F8A-B5E6-D7A1F0C3E2B9} |
| Trwałość (macOS) | ~/Library/LaunchAgents/com.apple.windowserver.helper.plist; binarny w ~/.local/share/runtime/com.apple.runtime |
| Znaczek jednorazowy | /tmp/.analytics_state, %TEMP%\analytics_state (okno 20 357 s) |
| Poproś o podpis | HTTPS GET, przypięty IPv4, User-Agent: node-fetch/2.6 |
| Plik etapu 1 | _polyfill.js, SHA-256 392dc9ec85042ce1796bfa9b8c7bf6e05c7710579aab8b7b1eb73788683883af |
| Plik bez odniesień | lib/telemetry.js, SHA-256 2266c9b8e199daebe31a9afcb61d9b0d76706b63c92312fc8223d22de42e63c7 |
| Etap 2 (Linux x64) | SHA-256 7e486657f30594afda379b97030252a09a19fe8055e25c9e371544f59bd8e9e3 |
| Etap 2 (Linux arm64) | SHA-256 aafc37589c0d21fb729761a1579ca3b278b95bce152aacfa29243ffd27f5eeb7 |
| Etap 2 (macOS) | SHA-256 c214746c74cae8ece8bdaf69aa05da4db6ce013f9e77452d1eed1a002fd9ba00 |
| Etap 2 (Windows) | SHA-256 d632c2c0c7801c3da57cf849fe4b4ca8351d9a7fe73c31050bf5dbcc96a16791 |
Nazwy pakietów
Atrybucja i obserwowane zachowanie
W grę wchodzą dwa konta npm. Dziewiętnaście nieopublikowanych nazw zostało opublikowanych przez jedno konto; a.poltoradnev-package-c Został ponownie zarejestrowany 2 sierpnia pod inną nazwą konta i inną domeną e-mail. Kod ma tę samą genezę w obu przypadkach, a druga rejestracja zawiera tych samych hostów dostarczających, te same domeny zapasowe DNS, tę samą konstrukcję ścieżki porzucania i to samo oznaczenie „run-once”.
Ponownie opublikowana para pokazuje również sposób jej montażu. Wersje 0.0.2 oraz 33.9.5 są identyczne bajtowo, poza ciągiem wersji w pakiet.jsoni indeks.js wysłane jako 0.0.2 deklaruje const WERSJA = „33.9.5”Oba artefakty zostały wycięte z jednego drzewa źródłowego i później ponumerowane. Nie ma 0.0.2 historia rozwoju dla 0.0.2 zwolnić do reprezentowania.
Numeracja wersji w całym zestawie opiera się na tej samej logice. Nazwy pakietów w tej kampanii oznaczają elementy, które istniałyby w organizacji, a nie w rejestrze publicznym: zestaw komponentów interfejsu użytkownika, konfiguracja ESLint, sonda SLA, pakiet nazwany imieniem osoby. Gdy kompilacja rozwiązuje zależność według nazwy i konsultuje rejestr publiczny oraz rejestr prywatny, wygrywa ta o wyższym numerze wersji. Nazwa utworzona w 0.0.1 w poniedziałek i niosąc 12.9.6 we wtorek jest gotowy na takie porównanie.
Dwie fale publikacji różnią się również w sposób sugerujący iterację. Wcześniejszy kod nazwał swój plik ładunku setup.js i wymieniono pięć hostów dostarczających; bieżący plik ma nazwę _polyfill.js i wymienia trzy. Wcześniejsza wersja usuwała usunięty plik pięć sekund po uruchomieniu, pozostawiając proces uruchomiony z usuniętego inoda; obecna wersja tego nie robi. Nieodwołany lib/telemetry.js pozostaje w archiwum tar, nadal wysyłany, nie jest już podłączony.
Warto przedtem poczynić jedną obserwację dotyczącą wyłączników awaryjnychcistylko dlatego, że kłóci się z powszechnym odczytaniem. WYŁĄCZ_TELEMETRIĘ, ANALITYKA_OPT_OUT, NIE_ŚLEDŹ Są one honorowane i sprawdzane przed podjęciem jakichkolwiek innych działań. Badacz, którego środowisko analityczne ustawia którykolwiek z nich, obserwuje pakiet, który nie wykonuje żadnych działań.
Wpływ i to, co potrafią zrobić obrońcy
Praktyczne konsekwencje uruchomienia mechanizmu w momencie importu są wąskie i warto je omówić osobno. npm install –ignore-scripts Zapobiega uruchamianiu skryptów cyklu życia i jest to dobra rada. Nie ma to tutaj żadnego efektu, ponieważ ten kod nie używa skryptu cyklu życia. Ładunek jest uruchamiany, gdy kod aplikacji, test, pakiet lub linter najpierw importuje moduł. W przypadku modułu CI, który instaluje, a następnie natychmiast kompiluje, te dwa procesy różnią się w ciągu kilku sekund.
W przypadku polowań trwałe sygnały mają charakter strukturalny, a nie dosłowny. Hosty, nazwa pliku i ścieżki upuszczania ulegną zmianie; te kształty są trudniejsze do zmiany:
- Punkt wejścia modułu, którego ostatnim poleceniem jest spróbuj { wymagaj(“./x”); } złap (_) {} wokół pliku, który nie jest częścią eksportowanego API. Pakiet z prawdziwym polyfillem importuje go na początku i używa jego wyniku. Pobieranie każdego błędu z importu na końcu pliku nie jest obsługą błędów.
- Łańcuchy hostów zmontowane przez .dołączyć("") z tablicy fragmentów. Prawidłowy kod nie ma powodu dzielić nazwy hosta na elementy tablicy.
- Pakiet, którego zadeklarowane zależności są puste, ale który sięga po https, dns, proces_potomny w momencie importu. Całym odkryciem jest pobieranie i wykonywanie w pakiecie reklamującym komponent interfejsu użytkownika.
- Numery wersji nie są zgodne z wiekiem pakietu. Nazwa, która po raz pierwszy została opublikowana kilka dni temu przy dwucyfrowej liczbie wydań głównych, bez żadnych późniejszych wydań, opisuje coś innego niż jej rozwój.
- Pisze do / Var / tmp or % Temp% następnie chmod do 0755 i odłączony spawn. Sekwencja ta jest krótka, uporządkowana i rzadko występuje łącznie jako łagodna.
Na hostach z systemem Windows dostępne są dwa tanie i wiarygodne testy. Artefakty trwałości to stałe ciągi znaków i żaden z nich nie znajduje się w czystym systemie: zaplanowane zadanie w \Microsoft\Windows\Multimedia\SystemSoundsService, wartość klucza Run o nazwie Usługa dźwięków systemowychi plik wykonywalny o tej nazwie pod %APPDATA%\Microsoft\Windows\Motywy\Oryginalna usługa audio systemu Windows nie znajduje się w żadnym z tych miejsc. Po drugie, moduł ładujący używa stałego mutexu o pojedynczej instancji, Global\{7A3B9E1F-C2D4-4F8A-B5E6-D7A1F0C3E2B9}; jego obecność na hoście jest wskaźnikiem, a ponieważ moduł ładujący traktuje istniejący mutex jako „już uruchomiony”, jego wcześniejsze utworzenie jest skuteczną krótkoterminową szczepionką, podczas gdy planowane jest przeprowadzenie naprawy.
Wykrywanie na trzecim etapie to trudniejszy problem i warto go jasno określić. Zgodnie z informacjami podanymi przez publiczną analizę, dane są odszyfrowywane i mapowane w pamięci, a nie zapisywane na dysku, więc skanowanie plików i analiza dysków nie wykryją ich obecności. Nadal jednak widoczny jest ślad własny programu ładującego — wpisy trwałości, mutex i żądania wychodzące do hostów dostarczających lub domen DNS-TXT.
W środowiskach, które rozwiązują zależności zarówno z rejestru prywatnego, jak i publicznego, łagodzenie nie zmienia się pod wpływem: nazw wewnętrznych zakresu, których nazwa publiczna nie może spełnić, oraz przypinania rozwiązywania do rejestru wewnętrznego dla tych zakresów. Opisane powyżej zachowanie polegające na rozszerzeniu wersji działa tylko wtedy, gdy wyższa wersja publiczna może wygrać nazwę.
Na koniec, warto uważnie przeczytać informację o niepublikowaniu, a nie traktować jej jako zakończenia. Dziewiętnaście nazw opuściło rejestr w ciągu dwudziestu pięciu sekund, a jedna powróciła dzień później na nowym koncie, z nienaruszoną infrastrukturą dostarczania. Usunięcie pakietów nie oznacza usunięcia operacji; hosty kontynuowały obsługę każdego etapu w trakcie pisania tego tekstu. Każde drzewo zależności, które rozwiązało jedną z tych nazw między 31 lipca a 1 sierpnia, należy traktować jako mające możliwość wykonania etapu pierwszego, niezależnie od tego, czy nazwa ta nadal istnieje.
Referencje
- Wielosilnikowa analiza modułu ładującego systemu Windows — źródło łatania AMSI/ETW, wykonywania refleksyjnego w pamięci i szczegółów mutexu przypisanych powyżej.
- dokumentacja skryptów npm — wydarzenia cyklu życia, z których ta kampania nie korzysta.
- dokumentacja instalacji npm — okładki –Ignore-scripts i jego zakres.




