Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!

ForceMemo: malware ukrywany w repozytoriach przez force-push

30 marca 2026, 00:20 | Aktualności | 1 komentarz

Badacze bezpieczeństwa z StepSecurity odkryli nową kampanię malware, w której atakujący przejmuje masowo konta programistów na GitHub i wstrzykuje złośliwe oprogramowanie do setek repozytoriów. Pierwszą aktywność odnotowano 8 marca 2026 roku, ale według ustaleń badaczy kampania wciąż trwa i przejmowane są kolejne repozytoria. Kampania – nazwana przez badaczy ForceMemo – wykorzystuje nietypową technikę force-push do ukrywania zmian w repozytoriach.

TLDR:

  • Masowa kampania ForceMemo przejmuje konta GitHub i infekuje setki repozytoriów Python.
  • Malware jest wstrzykiwany przez force-push, co utridnia zauważenie zmian w historii commitów.
  • Złośliwe oprogramowanie uruchamia się m.in. przy pip install lub uruchomieniu kodu z repozytorium.
  • Kod jest silnie obfuskowany i wykorzystuje blockchain Solana jako infrastrukturę C2.
  • Kampania jest najprawdopodobniej powiązana z malware GlassWorm, które wykradało m.in. tokeny GitHub.
  • Atak wciąż trwa, przejmowane są kolejne repozytoria.

Atak celuje w projekty Python – w tym aplikacje działające w frameworku Django oraz pakiety PyPI. Malware umieszczane jest w zaciemnionej (obfuskowanej) formie do plików takich jak setup.py, main.py i app.py. Każdy, kto wykona polecenie pip install w katalogu zainfekowanego repozytorium lub sklonuje je i wykona kod, uruchomi malware.

Rys. 1 – przykład złośliwego kodu dopisanego na końcu pliku, źródło: stepsecurity.io

Jeden z użytkowników Reddita powiązał złośliwe commity w swoich repozytoriach z zainstalowaniem złośliwej wtyczki w Cursor (edytorze kodu opartym na Visual Studio Code i korzystającym z tych samych wtyczek).

Może to sugerować, że konta były przejmowane przy użyciu tokenów wykradzionych przez opisywane przez nas malware GlassWorm. Było ono rozpowszechniane w złośliwych rozszerzeniach do VS Code (oraz jego forków, takich jak właśnie Cursor). 

Gdy właściciel przejętego konta posiada wiele repozytoriów z projektami w Pythonie, złośliwe oprogramowanie umieszczane jest w wielu z nich. 

Po przejęciu konta programisty rozwijającego dany projekt na GitHub, atakujący wykonuje rebase ostatniego commita dodając do plików malware. Taki commit jest następnie wypychany z użyciem force-push, dzięki czemu zmiany zostają wprowadzone w oryginalnym repozytorium, jednak trudniej jest je od razu dostrzec. Tytuł ostatniego commita i jego autor są zachowane z oryginału, więc na pierwszy rzut oka nie wzbudzają podejrzeń.

Można jednak zauważyć rozbieżności dat – przykładowo w repozytorium amirasaran/django-restful-admin najnowszy (złośliwy) commit pochodzi z 10 marca 2026, jednak stanowi (ponowny) merge pull requestu z listopada 2024.

Rys. 2 – ponowny merge, źródło: github.com

Wstrzyknięty kod został zaciemniony trzykrotnie. Zakodowano go do postaci base64, skompresowano (zlib) oraz zaszyfrowano (XOR). Nazwy zmiennych to losowe ciągi 15 znaków, ale jedna z nich powtarza się we wszystkich zidentyfikowanych repozytoriach. Możliwe jest więc ich wyszukanie na GitHub.

Rys. 3 – ten sam złośliwy kod w wielu repozytoriach, źródło: stepsecurity.io

Po deobfuskacji malware najpierw sprawdza ustawienia języka i strefę czasową. Jeśli wykryje rosyjskie środowisko, nie wykonuje żadnych dalszych działań. Ponadto złośliwy kod zawiera komentarze w języku rosyjskim:

  • “Эмуляция объекта Buffer из Node.js” (Emulacja obiektu Buffer z Node.js);
  • “Получение подписей для адреса Solana” (Pobieranie podpisów dla adresu Solana);
  • “Проверка, находится ли система в России” (Sprawdzanie, czy system działa w Rosji).

Może to sugerować, że za kampanią stoją atakujący z Rosji lub stwarzający takie pozory.

Zamiast łączyć się z “klasycznym” serwerem C2 (który można na wiele sposobów blokować), malware do przekazywania instrukcji wykorzystuje blockchain Solana. Odpytuje endpointy Solana RPC o transakcje dla zapisanego na stałe (hardcoded) adresu. W kodzie zapisano 9 różnych endpointów:

  • api[.]mainnet-beta[.]solana[.]com,
  • solana-mainnet[.]gateway[.]tatum[.]io,
  • go[.]getblock[.]us,
  • solana-rpc[.]publicnode[.]com,
  • api[.]blockeden[.]xyz,
  • solana[.]drpc[.]org,
  • solana[.]leorpc[.]com,
  • solana[.]api[.]onfinality[.]io,
  • solana[.]api[.]pocket[.]network.

Czyni to infrastrukturę C2 bardziej odporną na zablokowanie pojedynczego adresu. Wykorzystanie blockchaina powoduje, że atakujący może dowolnie aktualizować URL payloadu poprzez publikację nowej transakcji – a jej usunięcie jest (praktycznie) niemożliwe. Używany w tej kampanii adres portfela Solana jest tym samym adresem, co wskazany przez badaczy z Koi adres używany w ramach kolejnej fali kampanii GlassWorm.

Malware pobiera adres URL z blockchaina. Na urządzeniu użytkownika pobierane i uruchamiane jest także Node.js. Następnie z uzyskanego adresu pobierany jest główny payload (w formie zaszyfrowanej), a w nagłówkach odpowiedzi serwera przesyłany jest klucz do jego odszyfrowania.

Pełna historia instrukcji C2 jest trwale zapisana jako transakcje w Solana. Badaczom udało się je pobrać. Najwcześniejsza transakcja pochodzi z 27 listopada 2025 – ponad trzy miesiące przed pierwszymi przejętymi repozytoriami. Adres ma łącznie 50 transakcji – atakujący regularnie aktualizuje adres URL payloadu. Zdekodowane URL payloadów ujawniają 6 adresów IP serwerów C2.

Każde memo zawiera zakodowany w base64 URL wskazujący na aktualny serwer dostarczający payload. Badacze ustalili adresy, z których korzystano w tej kampanii:

  • 45[.]32[.]151[.]157 – aktywny w grudniu 2025 (najwcześniejszy)
  • 45[.]32[.]150[.]97 – aktywny w lutym 2026
  • 217[.]69[.]11[.]57 – aktywny w lutym 2026
  • 217[.]69[.]11[.]99 – aktywny w lutym-marcu 2026
  • 217[.]69[.]0[.]159 – aktywny 13 marca 2026 
  • 45[.]76[.]44[.]240 – aktywny 13 marca 2026

Adresy IP 45.x należą do hostingu Vultr, a 217.69.x to rosyjski zakres. 

Choć nie był to atak wycelowany w konkretny projekt, atakującym udało się wdrożyć złośliwy kod do około 200 repozytoriów (część z nich wycofała już wprowadzone zmiany). Szczególnie interesujący jest sposób działania infrastruktury C2 – a ze względu na jego podobieństwa (w tym pokrywający się adres portfela) do kampanii GlassWorm – można przypuszczać, że to po prostu kolejny krok atakujących po wykradzeniu poświadczeń nieświadomych niczego programistów.

Jeśli słuszne są przypuszczenia o wykradaniu tokenów GitHub przez złośliwe wtyczki – główną rekomendacją byłoby ograniczanie ich liczby do niezbędnego minimum. Warto przyjąć taką strategię niezależnie od tego, czy akurat one tutaj “zawiniły”. Polecamy również nasze dotychczasowe teksty o złośliwych wtyczkach.

W kwestii tokenów GitHub, zwracamy uwagę na możliwość szczegółowej kontroli ich uprawnień – warto korzystać z wielu tokenów z minimalnymi koniecznymi uprawnieniami:

Rys. 4 – tworzenie tokenu na GitHub

Takie rozwiązanie ułatwi też szybkie zablokowanie dostępu i może zmniejszyć szkody w przypadku wykradnięcia/wycieku pojedynczego tokenu. Wrażliwym projektom polecamy skorzystanie z kluczy SSH (najlepiej zabezpieczonych hasłem i przechowywanych na tokenie sprzętowym, np. YubiKey).

IOC

Portfel Solana (C2): BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC

Portfel Solana, z którego zamieszczano konfigurację: G2YxRa6wt1qePMwfJzdXZG62ej4qaTC7YURzuh2Lwd3t

Nazwa zmiennej w kodzie: lzcdrtfxyqiplpd

Adresy IP:

  • 45[.]32[.]151[.]157
  • 45[.]32[.]150[.]97
  • 217[.]69[.]11[.]57
  • 217[.]69[.]11[.]99
  • 217[.]69[.]0[.]159
  • 45[.]76[.]44[.]240

Źródła:

~Tymoteusz Jóźwiak

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



Komentarze

  1. devops

    Dzięki za kompleksowe opracowanie – dobra robota!
    Podsumowując: force‑push nie jest wektorem ataku, tylko mechanizmem użytym po przejęciu kont. Przy poprawnie wdrożonych branch protections, reviews i audycie zdarzeń GitHuba, nawet taki scenariusz zostawia ślady. Problemem tutaj jest supply chain + credentials hygiene, nie sam workflow DevOps.

    Odpowiedz

Odpowiedz