728 x 90

Czego uczą nas wycieki ransomware Conti i M0yv?

Czego uczą nas wycieki ransomware Conti i M0yv?

Luty 2022 był dla społeczności ransomware przełomowym miesiącem. To właśnie w tym miesiącu wyciekły bowiem kody źródłowe aż dwóch ważnych rozwiązań ransomware – i zarazem dwóch bardzo różnych technicznie podejść do tego biznesu.

Aby dobrze zrozumieć kontekst omawianych poniżej wydarzeń, cofnijmy się do końcówki wakacji 2020, gdy to opublikowaliśmy trzecią i czwartą część naszego cyklu o ransomware.

W części trzeciej omawialiśmy zagadnienia związane z enumeracją zasobów, w czwartej zaś z unikaniem wykrycia. Oba w przypadku ransomware bardzo silnie się przenikają – chodzi bowiem o to, aby użytkownik zauważył efekty działania tego oprogramowania w momencie, w którym jest już „za późno”.

We wspomnianej części trzeciej wprost postawiliśmy kluczowe pytanie, co jest celem autora?

  • proste rozwiązanie do infekowania pojedynczych komputerów (które w przypadku większych projektów trzeba wspomagać działaniami manualnymi)
  • zaawansowane rozwiązanie, stawiające przede wszystkim na samodzielne rozprzestrzenianie się wirusa, oraz skuteczne ukrywanie jego obecności w systemie przed oprogramowaniem antywirusowym i innym zabezpieczającym

Od tego bowiem zależą nie tylko jakieś pojedyncze szczegóły techniczne, ale cała architektura tworzonego rozwiązania.

Wycieki kodu Conti i M0yv pokazują nam konsekwencje tego wyboru w praktyce

W przypadku Conti, wyciek z przełomu lutego i marca jest tak naprawdę już drugim wyciekiem – wcześniej bowiem, w sierpniu 2021, wyciekło 20 gigabajtów materiałów instruktażowych dla partnerów, dzięki którym mieli oni realizować projekty niezależnie od autorów:

Już tamten wyciek rzucił sporo światła na ich cały model działania:

  • stosunkowo proste rozwiązanie techniczne do właściwego szyfrowania, nie potrafiące się samodzielnie rozprzestrzeniać (granica jego zasięgu to zaszyfrowanie danych na znalezionych udziałach sieciowych), ani skutecznie maskować swojej obecności do odpowiedniego momentu (konieczny jest więc manualny deployment rozwiązania w tymże odpowiednim momencie)
  • cały proces dotarcia na serwery ofiary (jak i późniejszej obsługi płatności) realizowany manualnie (do tego właśnie autorom potrzebni są partnerzy, dostarczający najbardziej deficytowego zasobu: czasu)
  • dodatkowym straszakiem dla ofiar, poza zaszyfrowaniem danych, jest groźba ich publikacji w Internecie

Konsekwencją takiego modelu działania jest brak skalowalności. Oczywiście skoro mowa o działalności nielegalnej, ta skalowalność nie wydaje się tak naprawdę potrzebna – celem nie jest bowiem dotarcie ze swoim produktem do każdego, kto mógłby zapłacić chociaż 10, 100 czy 1000 dolarów za odszyfrowanie danych. Wręcz przeciwnie, obsługa takich płatności stanowiłaby tylko niepotrzebne obciążenie i ryzyko popełnienia błędu przez autorów wskutek rutyny.

Prawdziwym celem jest dotarcie do stosunkowo wąskiego grona tych firm, które mogą zapłacić naprawdę duże pieniądze za odzyskanie danych, jak również za ich niepublikowanie – dzięki czemu lista aktywnych w danym momencie klientów jest bardzo krótka i łatwa do obróbki manualnej:

I takie podejście ma sens, dopóki myślimy o ransomware jako o produkcie komercyjnym – wprawdzie nielegalnym i wciskanym ofiarom przymusowo, ale poza tym bardzo podobnym do tych legalnych, a więc nastawionym na maksymalizację zysków. Zwłaszcza w sytuacji, gdy systemy Windows są coraz bezpieczniejsze, a więc implementacja pełnej skalowalności oznacza nieporównywalnie większą inwestycję w rozwój takiego oprogramowania, niż 10 czy 20 lat temu (a przecież już Stuxnet, „odpalony” w 2009 roku, był oszacowany na 6 miesięcy pracy i 30 programistów).

Natomiast tak zaprojektowane rozwiązanie ransomware zupełnie nie nadaje się do przystosowania do innych celów, gdzie zamiast zysków finansowych, celem jest skalowalność sama w sobie:

  • wszelkiego rodzaju oprogramowanie wojenne i wspomagające działania wojenne (jak np. NotPetya czy Hermetic, czyli wipery udające ransomware, użyte do ataków na Ukrainę w odpowiednio 2017 i 2022)
  • działalność szpiegowska i związane z nią zacieranie śladów (gdzie uniknięcie wykrycia i perfekcyjne zgranie poszczególnych kroków w czasie może wręcz stanowić o czyimś życiu, a przynajmniej zachowaniu wolności)
  • haktywizm
  • bezinteresowne (przynajmniej w sensie braku osobistych korzyści materialnych) sianie spustoszenia na większą skalę (np. w ramach realizacji poglądów politycznych, społecznych, czy dowolnych innych celów autora)

Czy to oznacza, że Conti jest słabe technologicznie?

Bynajmniej. Brak zdolności rozprzestrzeniania się, czy zaawansowanego ukrywania swojej obecności, są oczywiście dość poważnymi wadami, z drugiej strony ma to cały szereg nieco mniej oczywistych zalet:

  • kod źródłowy całego rozwiązania jest niewielki, bardzo elegancko napisany (z wyjątkiem pewnych fragmentów, np. sposobu osadzenia zmiennej z kluczem publicznym), przejrzysty i bardzo łatwy do analizy, jak również wprowadzania własnych modyfikacji
  • kod wynikowy jest również niewielki, a więc łatwiejszy do szybkiego transferu w różne miejsca i ukrycia przed programami antywirusowymi – na upartego dałoby się z niego nawet zrobić shellcode
  • nie da się pominąć aspektu ekonomicznego: stworzenie tego kodu było relatywnie tanie (w sensie zarówno ilości i wartości poświęconego czasu, jak i wymaganych kwalifikacji autorów) – większość łącznych kosztów infekcji jest w tym modelu przerzucana na partnerów (w postaci dużo większego zapotrzebowania na ich czas i – jak wynika z również wyciekłych czatów – dość intensywną pracę nad każdym projektem)

Można wręcz powiedzieć, że większość tego kodu napisana jest w sposób książkowy. Bardzo dobrym pomysłem – z jakiegoś powodu rzadko spotykanym w innych rozwiązaniach ransomware – jest wykorzystanie makr Glibc do obsługi list (z pliku queue.h) do obsługi struktur danych podczas enumeracji dysków i udziałów sieciowych, a w szczególności do zarządzania wątkami. Proste i niezwykle eleganckie:

namespace filesystem {
	typedef struct drive_info_ {
		std::wstring RootPath;
		TAILQ_ENTRY(drive_info_) Entries;
	} DRIVE_INFO, *PDRIVE_INFO;
	typedef TAILQ_HEAD(drive_list_, drive_info_) DRIVE_LIST, * PDRIVE_LIST;
}
namespace threadpool {
	enum THREADPOOLS {
		LOCAL_THREADPOOL,
		NETWORK_THREADPOOL,
		BACKUPS_THREADPOOL
	};
	typedef TAILQ_HEAD(task_list_, task_info_) TASK_LIST, * PTASK_LIST;
	typedef struct task_info_ {
		std::wstring FileName;
		TAILQ_ENTRY(task_info_) Entries;
	} TASK_INFO, * PTASK_INFO;
	typedef struct threadpool_info_ {
		PHANDLE hThreads;
		SIZE_T ThreadsCount;
		SIZE_T TasksCount;
		CRITICAL_SECTION ThreadPoolCS;
		TASK_LIST TaskList;
		BOOL IsWaiting;
		HANDLE hQueueEvent;
	} THREADPOOL_INFO, * PTHREADPOOL_INFO;
	BOOL Create(INT ThreadPoolId, SIZE_T ThreadsCount);
	BOOL Start(INT ThreadPoolId);
	VOID Wait(INT ThreadPoolId);
	VOID Delete(INT ThreadPoolId);
	VOID SuspendThread(INT ThreadPoolId);
	INT PutTask(INT ThreadPoolId, std::wstring Filename);
}

W efekcie Conti ma jedną z najprostszych do zrozumienia, a zarazem najbardziej efektywnie działających implementacji wielowątkowości. Nie jesteśmy wprawdzie prawnikami, ale zaryzykujemy tezę, że autorzy nie odważą się pozwać nikogo do sądu za skopiowanie tego kodu i użycie w całkiem innym celu 🙂

Równie pomysłowe jest użycie własnych makr do uproszczenia sposobu, w jaki Conti odróżnia pliki baz danych i obrazów maszyn wirtualnych od wszystkich pozostałych:

		OBFW(L".4dd"),
		OBFW(L".4dl"),
		OBFW(L".accdb"),
		OBFW(L".accdc"),
		OBFW(L".accde"),

aby następnie (w metodzie locker::Encrypt) w oparciu o to kryterium, oraz o wielkość pliku, zdecydować, jak dany plik ma być zaszyfrowany:

  • w całości (wszystkie pliki bazodanowe oraz o wielkości poniżej 1 megabajta)
  • tylko 50% (pliki o wielkości powyżej 5 megabajtów)
  • tylko 20% (wszystkie obrazy maszyn wirtualnych)
  • tylko nagłówek (pliki o wielkości pomiędzy 1 a 5 MB)

Od strony samej implementacji jest to zupełnie inne podejście niż w większości innych ransomware, gdzie lista rozszerzeń jest statyczną tablicą, przez co kod jest albo jednowątkowy, albo dużo mniej czytelny (co wynika ze specyfiki języka C, który nie wspomaga w żaden sposób zarządzania pamięcią w kontekście wielowątkowości). Tutaj proste makra budują bardzo sprytną strukturę danych, po której można swobodnie iterować, sprawdzając, czy dany plik nie został już w międzyczasie zaszyfrowany przez inny wątek (który np. dostał akurat mniejsze pliki i przetwarza je szybciej).

Zaś od strony architektury, algorytm ten jest bardzo sprytnym podejściem do problemu efektywności czasowej procesu szyfrowania, o którym wspominaliśmy w części trzeciej naszego cyklu.

Jeszcze biznes czy już sztuka?

Na trzy tygodnie przed wyciekiem Conti, na pewnym forum ukazał się bardzo ciekawy post, do którego dołączony był jeszcze ciekawszy załącznik:

Czyli, delikatnie skracając:

Tu autor. Zadecydowaliśmy o publikacji kluczy dla rodzin ransomware Egregor, Maze i Sekhmet.

Oprócz tego, oto dość nieszkodliwy kod źródłowy polimorficznego, modułowego infektora plików x86/x64, wykrywanego przez antywirusy jako Win64/Expiro. W rzeczywistości to nie Expiro tylko m0yv.

(…)

Podkreślam że wyciek ten jest planowany i nie ma żadnego związku z ostatnimi aresztowaniami. Kod źródłowy m0yv jest bonusem, ponieważ od lat nie było [publikacji] żadnego większego kodu oprogramowania rezydentnego.

Żaden z członków naszego zespołu już nigdy nie wróci do tego rodzaju aktywności, przyjemnie się z wami pracowało. Cały kod źródłowy [pozostałych] narzędzi, jakie zostały kiedykolwiek stworzone, został usunięty.

Innymi słowy, post ten jest pożegnaniem autorów, którzy zapewne uznali, że zarobili już wystarczająco dużo i chcą bezpiecznie wyjść z inwestycji, dopóki jeszcze mogą. Przypuszcza się, że pożegnanie to jest szczere, gdyż w dołączonych do niego załącznikach rzeczywiście znajdowały się wspomniane klucze i kod źródłowy.

O ile dla ofiar Egregora czy Maze najważnejsze były te klucze, pozwalające na odzyskanie danych bez płacenia okupu, o tyle pod względem czysto technologicznym zdecydowanie najciekawszym elementem jest kod źródłowy m0yv. Co można o nim powiedzieć?

  1. Jest to prawdopodobnie najbardziej zaawansowany kod wirusa, jaki autor tego tekstu widział od roku 2004 (gdy współpracował z branżą antywirusową). Sama tylko implementacja polimorfizmu to dzieło sztuki (!), jakiego nie spotyka się w dzisiejszych wirusach.
  2. Główny autor tego rozwiązania „ma w małym palcu” różnice w działaniu 32- i 64-bitowych systemów Windows – widać to po wielu miejscach (np. plik trashgen.cpp). I nie wahamy się go całkiem serio określić ekspertem klasy światowej. Co – niestety dla niego – dość mocno zawęża krąg możliwych autorów.
  3. Zastosowane w kodzie techniki, dobór nowoczesnych algorytmów kryptograficznych, liczne komentarze wyjaśniające sposób działania poszczególnych fragmentów, jak i wybór zastosowanych bibliotek open source wskazują też, że główny autor:
    • jest Rosjaninem
    • najprawdopodobniej ma wyższe wykształcenie, w tym miał zajęcia z teorii systemów operacyjnych, programowania w C lub C++ dla Windows i podstaw kryptografii
    • prawdopodobnie jest osobą młodą (możliwe nawet że przed 30-tką lub niedługo po) – bądź też zdobył to wykształcenie stosunkowo niedawno (maksymalnie w ostatnich ok. 15 latach)
    • i niewątpliwie jest osobą wybitnie zdolną
  4. Po dokładniejszej analizie widać pewne niekonsekwencje w kodzie, wskazujące na to, że było jeszcze co najmniej 2 autorów „wspomagających”. Pierwszy zapewne składał m0yv z kilku osobnych części, drugi najprawdopodobniej był jednocześnie testerem – widać to po kilku elementach:
    • sposobie łączenia kodu w czystym C z kodem C++, a także po kilku miejscach, które nie pasują do reszty np. module impersonator.cpp (pierwszy autor wspierający)
    • implementacji logowania zdarzeń, mechanizmu wyłączającego działanie wirusa w zależności od języka (dla zachowania neutralności nie ujawniamy szczegółów tego algorytmu), czy modułu exe2shellcode (drugi autor)
  5. Przede wszystkim jednak, to jest pełnoprawny przykład tego, jak powinno się podchodzić do skalowalności ransomware – a więc rozwiązanie, które w przeciwieństwie do Conti, nie wymaga wspomagania działaniami manualnymi przez partnerów. Dzięki temu, gdyby zaszła potrzeba jego przystosowania do działania na szerszą skalę – np. na potrzeby wspomagania kinetycznych działań wojennych – m0yv się jak najbardziej do tego nadaje.
  6. Przy tym wszystkim, m0yv… nie jest aktywnym programem typu ransomware. Dlaczego? Naszym zdaniem jest on przede wszystkim niedokończony – przypuszczalnie m0yv jako całość został stworzony w kwietniu 2020 (zaś niektóre elementy w 2019) i od tamtego czasu był aktywnie rozwijany aż do ataku na Colonial Pipeline, którego konsekwencje cała światowa społeczność ransomware odczuwa do dziś. Daty modyfikacji plików już po tamtym ataku (tj. po końcówce kwietnia 2021) wskazują, że program przestał być rozwijany równomiernie – od tamtego czasu ktoś siadał do tego projektu co jakiś czas i dopisywał kolejne elementy, rekompilował kod itd., ale widać że autorom w pewnym momencie upadła cała dotychczasowa koncepcja jego wykorzystania.

Szczegółowy opis poszczególnych modułów m0yv i zastosowanych w nim algorytmów jest tematem na grubą książkę, stąd nie ma sensu nawet próbować na poważnie zaczynać go omawiać w kawałku artykułu. Jedno można o nim powiedzieć na pewno: jeśli chcesz zobaczyć prawdziwy polimorfizm na miarę XXI wieku i nauczyć się go implementować – daruj sobie wszystkie inne silniki wirusów i zacznij naukę właśnie od kodu m0yv.

Podsumowanie

Conti i m0yv to nie tylko różne rozwiązania techniczne – to wręcz dwie całkiem różne wizje prowadzenia biznesu związanego z ransomware. Obie te wizje łączy jednak bardzo wysoka jakość kodu – przejawiająca się, ponownie, w całkiem różnych aspektach, ale bezdyskusyjnie oba rozwiązania zostały stworzone przez profesjonalistów.

A to prowadzi nas wprost do głównej tezy, jaką postawiliśmy prawie 2 lata temu, rozpoczynając nasz cykl o ransomware: jeśli jesteś przeciętnym programistą, bez doświadczenia w technologiach związanych z bezpieczeństwem (także własnym!), a w ransomware fascynują Cię głównie kwoty podawane w różnych doniesieniach prasowych, to lepiej sobie odpuść. Jako programista w pełni legalnych rzeczy, jeśli tylko nie popełnisz jakichś poważnych błędów w rozwoju swojej kariery, w kilka lat bez problemu wejdziesz do grona 2% najlepiej zarabiających Polaków (co dalej, to już zależy, jak dobry jesteś w tym, w czym się specjalizujesz – górny 1% też jest jak najbardziej realny).

A jeśli powyższe słowa Cię nie przekonują, po prostu zajrzyj do tego artykułu, przejrzyj wszystkie 10 odcinków naszego cyklu i spróbuj przyswoić całą podaną tam wiedzę. Jeśli nie czujesz się na siłach, aby opanować coś biegle, ani nie masz pomysłu, gdzie szukać zaufanych partnerów do tego typu przedsięwzięć, to najprawdopodobniej wcześniej czy później popełnisz jakiś prosty, drobny błąd – a wówczas Twoja kariera w biznesie ransomware może zakończyć się podobnie jak kariera partnerów ransomware REvil:


Intencją autorów ani wydawcy treści prezentowanych w magazynie PAYLOAD nie jest namawianie bądź zachęcanie do łamania prawa. Jeśli popełniłeś lub masz zamiar popełnić przestępstwo, bądź masz wątpliwości, czy Twoje działania nie będą łamać prawa, powinieneś skonsultować się z najbliższą jednostką Policji lub Prokuratury, a jeśli są one związane z pieniędzmi, dla pewności również z Urzędem Skarbowym.

Nie zezwala się na użycie treści prezentowanych w magazynie PAYLOAD, ani produktów dostępnych w sklepie PAYLOAD, do celów popełniania przestępstw lub przestępstw skarbowych.