Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!
Malware atakujący Discord oraz popularne przeglądarki internetowe – szczegółowa analiza VVS Stealer
Badacze z Unit42 (Palo Alto Networks) opublikowali szczegółową analizę nowego zagrożenia jakim jest VVS Stealer (znany również pod nazwą VVS $tealer). Tym razem atakujący obrali za cel użytkowników platformy Discord. Malware, napisany w Pythonie oraz zaciemniony z wykorzystaniem komercyjnego narzędzia Pyarmor jest dystrybuowany za pomocą tejże platformy oraz sprzedawany za pośrednictwem Telegrama.
TLDR:
- Badacze z Unit42 przedstawili szczegółową analizę malware napisanego w Pythonie – VVS Stealer.
- Na szczególną uwagę zasługują wielowarstwowe metody obfuskacji kodu.
- Malware bierze na cel użytkowników platformy Discord oraz popularne przeglądarki (Chrome, Mozilla, Brave).
- Wśród wykradzionych danych znajdują się:
- Discord: dane identyfikacyjne użytkownika (username, ID, e-mail, nr telefonu, zdjęcie Avatara), powiązane karty płatnicze, konta PayPal, lista znajomych, lista serwerów, adres IP, nazwa hosta,
- przeglądarki: pliki cookies, historia przeglądania, zapisane hasła.

Oprogramowanie zostało zaprojektowane z myślą o wykradaniu danych z Discorda oraz przeglądarek internetowych.
Analiza wsteczna malware
Badacze z Unit42 poddali analizie próbkę malware dystrybuowaną jako paczka PyInstaller (sha256:c7e6591e5e021daa30f949a6f6e0699ef2935d2d7c06ea006e3b201c52666e07). Dużym wyzwaniem okazał się proces deobfuskacji i inżynierii wstecznej, głównie z powodu zastosowania narzędzia Pyarmor w wersji 9.1.4 (Pro), o czym opowiemy dalej. Na poniższym diagramie przedstawiono poszczególne etapy analizy malware.

Rozpakowanie binarnej paczki PyInstaller
Pierwszym etapem analizy było wyodrębnienie zawartości paczki PyInstaller. Narzędzie to służy do dystrybucji malware jako samodzielnego pliku wykonywalnego, zawierającego wewnątrz wszystkie niezbędne zależności oraz biblioteki. W ten sposób unika się potrzeby instalacji dodatkowych modułów po uruchomieniu, co zwiększa skuteczność infekcji. Oczywiście wiąże się to z większym rozmiarem pliku binarnego.
Za pomocą narzędzia pyi-archive_viewer badacze wyodrębnili następujące pliki:
- skompilowany kod pośredni Pythona o nazwie vvs (bytecode),
- bibliotekę python311.dll (wersja 3.11.5),
- plik pyarmor_runtime.pyd (Pyarmor w wersji 9.1.4 Pro).
Plik vss został pozbawiony 16-bajtowego nagłówka, a co za tym idzie bez przywrócenia prawidłowej struktury pliku, użycie dekompilatora nie przynosiło oczekiwanych efektów. Badacze, po uzyskaniu informacji o wersji Pythona dokonali rekonstrukcji nagłówka wprowadzając następujące dane:
- 0xA70D0D0A – magic number dla wersji Python 3.11.5,
- 0x00000000 – bity kontrolne,
- 0x00000000 – znacznik czasu,
- 0x00000000 – rozmiar pliku źródłowego.
W tym miejscu analitycy mieli odrobinę szczęścia – dekompilator pycdc, przy prawidłowo wypełnionej jedynie pierwszej sekcji danych (4-bajtowym magic number) zwrócił oczekiwany wynik (zdekompilowany kod). Pozostała część nagłówka nie była istotna. W przypadku użycia innego dekompilatora mogłoby się okazać konieczne odtworzenie pełnej struktury nagłówka pliku.

Proces dekompilacji
Po odtworzeniu struktury pliku vss.pyc badacze przeprowadzili proces przekształcenia kodu źródłowego do postaci czytelnej dla człowieka. Wykorzystali w tym celu dekompilator pycdc (będący częścią projektu Decompyle++). Za pomocą komendy pycdc.exe -c -v “3.11.5” “vvs.pyc” > “vvs.py” udało się odtworzyć kod źródłowy malware. W dalszym ciągu okazał się on silnie zaciemniony, dlatego analitycy użyli modułu ast.NodeVisitor, pozwalającego na automatyczne przeszukiwanie struktury logicznej programu (drzewo AST). Dzięki niemu wyodrębnili zaszyfrowany payload.

Analiza nagłówka ujawniła strukturę danych, niezbędną do odszyfrowania kodu malware. Zaznaczone fragmenty oznaczają kolejno:
- 0x00 – 0x01 – prefix PY,
- 0x02 – 0x07 – numer licencji,
- 0x09 – 0x0a – wersja Pythona,
- 0x14 – aktywny tryb Pyarmor BCC (o czym będzie później),
- 0x1c – 0x1f – początek payloadu (little-endian),
- 0x24 – 0x27 – parametr nonce dla algorytmu AES-128-CTR (pierwsze 4 bajty),
- 0x2c – 0x33 – parametr nonce dla algorytmu AES-128-CTR (pozostałe 8 bajtów),
- 0x38 – 0x3b – koniec payloadu (little-endian).
Klucz szyfrujący do algorytmu AES-128-CTR nie był generowany dynamicznie podczas uruchomienie oprogramowania, tylko został ściśle powiązany z numerem licencji (007444) oprogramowania zabezpieczającego (Pyarmor) i umieszczony na stałe w pliku pyarmor_runtime.pyd.
Po zdjęciu warstwy obfuskacji, okazało się, że główna logika malware została przykryta kolejną warstwą szyfrowania. Badacze wyciągnęli bytecode bezpośrednio ze zdekompilowanego pliku vss.py. Zarówno parametr nonce jak i klucz szyfrujący uzyskany w poprzednim etapie był nieprawidłowy. Atakujący musieli użyć innych parametrów, zaszytych wewnątrz ładunku.
Analitycy zidentyfikowali w pliku pyarmor_runtime.pyd stały ciąg bajtów, który okazał się prawidłowym kluczem szyfrującym w algorytmie AES-128-CTR. Do pełnego sukcesu pozostało odtworzenie wartości nonce. Parametr ten był unikalny dla każdego payloadu. Aby go odtworzyć należało przeprowadzić operację XOR pomiędzy stałą wartością umieszczoną w runtime Pyarmor (plik .pyd) a fragmentem danych zaszyfrowanego payloadu (ostatnie 12 bajtów).
Po zdjęciu kolejnej warstwy szyfrowania, badacze zauważyli, że ciągi dłuższe niż 8 znaków są również zamaskowane. W tym przypadku technika obfuskacji polegała na szyfrowaniu AES-128-CTR (ten sam klucz szyfrujący) oraz parametrem nonce na stałe umieszczonym w logice biblioteki .pyd. Po zdjęciu warstwy szyfrowania uzyskano m.in. adres serwera C2. O tym czy dany ciąg był zaszyfrowany decydował prefix 0x81.
Kolejną przeszkodą na drodze analityków było użycie trybu BCC (skrót ten oznacza najprawdopodobniej ByteCode-to-Compilation), który konwertuje większość metod i funkcji skryptu na ich odpowiedniki w języku C, kompilowane bezpośrednio do kodu maszynowego. Zainteresowanych szczegółami technicznymi odsyłamy bezpośrednio do raportu badaczy.
W wyniku przeprowadzonych działań, analitycy odtworzyli logikę metody odpowiedzialnej za pozyskanie kluczy szyfrujących, która dla języka Python mogłaby wyglądać następująco:

Malware VVS Stealer
Pierwszym elementem, który przykuł uwagę analityków był zaimplementowany mechanizm autodestrukcji, czyli czasu po którym malware samoistnie przestaje działać (31.10.2026). Można przypuszczać, iż jest to związane z czasem obowiązywania licencji.
Następnie, wyodrębniono strukturę żądań HTTP, gdzie parametr User-Agent był zdefiniowany na stałe jako:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36. Zabieg ten miał na celu maskowania żądań w legalnym ruchu sieciowym.
Tak jak zostało to wspomniane na samym początku, malware został przygotowany pod kątem eksfiltracji danych Discorda. W tym celu skanował system pod kątem wykrycia zaszyfrowanych tokenów znajdujących się w plikach .ldb oraz .log. Charakteryzują się one prefixem dQw4w9WgXcQ:. Z uwagi na fakt, że są to informacje wrażliwe, zostały zaszyfrowane.
Klucze szyfrujące znajdują się w pliku Local State. Malware, korzystając z faktu, że został uruchomiony na koncie zalogowanego użytkownika, wykorzystuje mechanizm Windows DPAPI (Data Protection Application Programming Interface), który nie wymaga dodatkowego uwierzytelnienia do wyciągnięcia parametrów klucza. Następnie, odzyskany klucz zostaje przekazany do algorytmu AES-GCM wraz z zaszyfrowanym tokenem Discord. W efekcie udało się otrzymać odszyfrowany token Discord.
Token umożliwia atakującemu przejęcie następujących danych:
- dane identyfikacyjne użytkownika (username, ID, e-mail, nr telefonu, zdjęcie Avatara),
- status subskrypcji NITRO (funkcje premium Discorda),
- powiązane karty płatnicze, konta PayPal, itp.,
- status weryfikacji konta,
- lista znajomych,
- lista serwerów,
- informacja na temat uwierzytelnienia dwuskładnikowego (czy jest aktywne),
- ustawienia regionalne (Locale),
- adres IP, nazwa hosta.
Zgromadzone informacje są serializowane do postaci obiektu JSON, a następnie przesyłane na kanał Discord kontrolowany przez atakującego. W tym celu wykorzystano mechanizm Webhook, pozwalający na ukrycie żądania w legalnym ruchu sieciowym.
Co ciekawe, malware zamyka wszystkie aktywne procesy aplikacji Discord, a następnie podmienia jej dane konfiguracyjne. Payload injection-obf.js zostaje pobrany z serwera C2. Jest on zamaskowany za pomocą narzędzia JavaScript Obfuscator Tool. Korzystając z deobfuscatora można uzyskać czytelną postać kodu.
Komponent discord_desktop_core w katalogu instalacyjnym platformy Discord zostaje zmodyfikowany zgodnie z instrukcjami pobranymi z serwera C2. W ten sposób atakujący uzyskują z jednej strony trwały dostęp do konta użytkownika, złośliwy skrypt będzie ładowany automatycznie podczas uruchamiania aplikacji Discord. Z drugiej strony mają możliwość przechwytywania sesji w czasie rzeczywistym, omijania mechanizmu MFA, itp.

Malware wykrada dane z blisko 20 różnych przeglądarek internetowych (w większości opartych na silniku Chromium), w tym popularnych Chrome, Edge, Brave, Mozilla Firefox, Opera. Atakujący przechwytują za ich pośrednictwem informacje zawierające:
- pliki cookies,
- historię przeglądania,
- zapisane hasła.
Tak pozyskane dane zostają spakowane do archiwum ZIP o nazwie [username]_vault.zip, a następnie przesłane na serwer atakującego, w analogiczny sposób jak w przypadku informacji przejętych z Discorda.
Persystencja
W celu zapewnienia stałej obecności w systemie, malware tworzy kopię w lokalizacji %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup. W ten sposób, po każdym ponownym uruchomieniu systemu, złośliwy kod będzie startował automatycznie.
Ponadto, wewnątrz kodu wykryto funkcję odpowiedzialną za wyświetlanie okienka z fałszywą informacją o napotkaniu błędu krytycznego, który wymusza na użytkowniku ponowne uruchomienie systemu. Restart spowoduje załadowanie aplikacji Discord, z ustawieniami wdrożonymi przez atakujących.

Analiza malware VVS Stealer pokazuje jak bardzo zaawansowane narzędzia są stosowane przez cyberprzestępców. W tym miejscu należy podkreślić kluczową rolę zespołu Unit42 w procesie odtworzenia kodu źródłowego malware. Dzięki ich pracy mamy możliwość zapoznania się ze szczegółami implementacyjnymi złośliwego oprogramowania.
W dzisiejszych czasach nie trzeba dysponować specjalistyczną wiedzą programistyczną, aby przeprowadzić skuteczny atak. Ewolucja modelu Malware-as-a-Service skutkuje gwałtownym wzrostem liczby incydentów oraz niskim progiem wejścia dla potencjalnych atakujących.
Źródło: unit42.paloaltonetworks.com
~_secmike

Fajna lektura, dzięki za informacje