Tofsee – modularny spambot

Data publikacji: 16/09/2016, Adam Krasuski

Tofsee, znany również pod nazwą Gheg, to kolejny analizowany przez nas botnet. Jego głównym celem jest rozsyłanie spamu, jednak może on wykonywać także inne zadania. Jest to możliwe dzięki modularnej budowie malware’u – składa się on z głównego pliku wykonywalnego (tego, którym infekuje się użytkownik), który później pobiera z serwera C2 kilkanaście dodatkowych bibliotek DLL rozszerzających działanie kodu poprzez nadpisywanie niektórych wywoływanych funkcji swoimi własnymi. Przykładem takiej DLL-ki może być moduł do rozprzestrzeniania się poprzez postowanie wiadomości na Facebooku i VKontakte (rosyjskim portalu społecznościowym).

Komunikacja bota z botmasterem odbywa się przy użyciu niestandardowego protokołu opartego na TCP. Pierwszą wiadomość zawsze wysyła serwer tuż po nawiązaniu połączenia – zawiera ona przede wszystkim jednorazowy 128-bajtowy klucz użyty do szyfrowania dalszych komunikatów. Nie da się zatem odkodować komunikacji, jeśli się jej nie słucha od początku.

W każdym momencie bot trzyma w pamięci listę zasobów. Początkowo jest ona niemal pusta i zawiera jedynie podstawowe informacje, jak identyfikator bota, ale szybko jest uzupełniana przez dane otrzymane od serwera w kolejnych wiadomościach. Zasoby przyjmują różne formy – może to być np. lista tematów do wykorzystania w mailu, ale i także biblioteki DLL rozbudowujące funkcje bota. Dodatkowo, jeden z zasobów – work_srv – zawiera listę adresów IP serwerów C2. Jest to jedna z pierwszych wiadomości wysyłanych przez serwer i, co ciekawe, może nie zawierać samego siebie (wówczas połączenie jest kończone i wybierany jest losowy serwer z listy). Tak też się zazwyczaj dzieje podczas połączenia z C2 zapisanym na stałe w próbce – pełni on zatem rolę „wskaźnika” na rzeczywiste serwery.

Wysyłane emaile są tworzone w sposób losowy – Tofsee wykorzystuje do tego celu specjalny język skryptowy – przykładowy plik znajduje się niżej, w analizie technicznej. Zawiera on wydzielone pola, które zostaną losowo zastąpione pewnymi ciągami znaków – np. %RND_SMILE zostanie zmienione na jedną z kilkunastu emotikon. Dzięki temu prostsze filtry spamowe mogą je przepuścić.

Analiza techniczna

Lista adresów IP serwerów C2 jest zapisana w samym pliku w postaci zaszyfrowanej. Algorytm szyfrowania jest bardzo prosty – opiera się na XOR-owaniu ze stałym kluczem.

decryptstr
Odszyfrowane dane to trzy stałe IP wraz z portem, który w analizowanej próbce był równy 443 dla wszystkich odkodowanych adresów. Prawdopodobnie więc bot próbuje uniknąć wykrycia poprzez używanie portu przeznaczonego dla ruchu SSL/TLS.

Protokół komunikacji

Po nawiązaniu połączenia TCP, pierwsza wiadomość wychodzi od serwera. Ma ona zawsze 200 bajtów długości. Wygląda jednak na to, że końcowe bajty są niewykorzystane i zarezerwowane – być może w celach późniejszej rozbudowy protokołu. Także w tym miejscu wykorzystana jest prosta obfuskacja zawartości poprzez operacje bitowe:

Odszyfrowane dane składają się na nastepującą strukturę (nie poznaliśmy znaczenia wszystkich pól):

Od tego momentu, cała komunikacja (zarówno wiadomości przychodzące, jak i wychodzące) jest szyfrowana 128-bajtowym kluczem z pierwszej wiadomości. Klucz ten ulega modyfikacji przy każdym wysłanym/odebranym bajcie, zatem nie da się odszyfrować komunikacji, jeśli się jej nie słucha od początku. XOR-owanie jest użyte w taki sposób, że jedna funkcja służy zarówno do szyfrowania, jak i deszyfrowania:

Parametry:

    • data – surowe dane
    • key – krótki, 7-bajtowy klucz, inicjalizowany przed pierwszą wiadomością bajtami „abcdefg”
    • main_key – 128-bajtowy klucz z powitania
    • it – liczba już odebranych/wysłanych bajtów

Wszystkie wiadomości (poza powitalną) składają się z nagłówka oraz właściwych danych. Nagłówek zawiera następujące pola:

Protokół wspiera kompresję danych, ale jest ona używana tylko dla większych wiadomości. Pola op, subop1 i subop2 to pewne stałe, definiujące typ wiadomości. W analizowanej próbce widać kod obsługujący wiele różnych typów, ale w praktyce jedynie nieliczne z nich są wykorzystywane.

Payload jest wysyłany zaraz po nagłówku. Jego dokładna struktura zależy od typu wiadomości – kilka z nich przedstawię poniżej.

Pierwsza wiadomość wysyłana przez bota ma typy {1,0,0} (kolejno op, subop1, subop2) i składa się na dość pokaźną strukturę:

Niektóre z nazw pól (np. lid_file_upd) dostaliśmy „za darmo”, ponieważ bot zapisywał je pod takimi właśnie indeksami do wewnętrznej struktury danych mapującej nazwy zmiennych na ich zawartość. Znaczenia innych musieliśmy się domyślić sami.

Odpowiedź serwera może mieć różną formę. Najprostsza z nich następuje gdy op=0 – oznacza to pustą odpowiedź (lub koniec transmisji składającej się z wielu wiadomości). Jeśli op=2, to serwer wysyła nam nowy zasób – payload wiadomości jest wówczas taką strukturą:

Zazwyczaj tuż po połączeniu się z C2 wpisanym na sztywno do próbki pierwszą wiadomością po powitalnej, jaką bot otrzymuje, jest pojedynczy zasób o nazwie work_srv. Znajduje się w nim lista kilku adresów IP oraz portów (już różnych niż 443), na których nasłuchują właściwe serwery C2. Wówczas następuje rozłączenie z dotychczasowym serwerem i po chwili bot rozpoczyna komunikację od nowa z losowym z świeżo otrzymanych serwerów C2.

Jeśli op=1, wiadomość ma różne znaczenie w zależności od subop2 oraz, dodatkowo, pierwszych czterech bajtów payloadu (które najwyraźniej w tym wypadku pełnią funkcję flag). Przykładowo, jeśli spełnione są następujące warunki: op=1, subop2&1=0, flags=4, to jest to żądanie C2, aby bot wysłał mu wszystkie posiadane zasoby. Odpowiedzią bota jest wówczas skonkatenowana lista zasobów o postaci podobnej do wyżej pokazanej, po czym serwer wysyła dziesiątki wiadomości typu 2 (zawierające zasób) – zasoby, których bot jeszcze nie ma.

Zasoby

Każdy zasób jest identyfikowany typem – niewielką liczbą (nie większą niż 40, chociaż większość jest nawet mniejsza niż 10) oraz krótką nazwą, np. „priority”. Z analizowanych przez nas typów najciekawsze to:

Typ 5

Zawiera pluginy w postaci bibliotek DLL. Ponieważ pojedyncze symbole będące pozostałościami po kompilacji zostały w nich zostawione, mogliśmy się łatwo domyślić, jakie zadania mają poszczególne pluginy. W czasie analizy Tofsee pobierał następujące pluginy:

Nazwa zasobu – numer Nazwa biblioteki Hash MD5 DLL-ki
1 ddosR.dll fbc7eebe4a56114e55989e50d8d19b5b
2 antibot.dll a3ba755086b75e1b654532d1d097c549
3 snrpR.dll 385b09563350897f8c941b47fb199dcb
4 proxyR.dll 4a174e770958be3eb5cc2c4a164038af
5 webmR.dll 78ee41b097d402849474291214391d34
6 protect.dll 624c5469ba44c7eda33a293638260544
7 locsR.dll 2d28c116ca0783046732edf4d4079c77
10 hostR.dll c90224a3f8b0ab83fafbac6708b9f834
11 text.dll 48ace17c96ae8b30509efcb83a1218b4
12 smtp.dll 761e654fb2f47a39b69340c1de181ce0
13 blist.dll e77c0f921ef3ff1c4ef83ea6383b51b9
14 miner.dll 47405b40ef8603f24b0e4e2b59b74a8c
15 img.dll e0b0448dc095738ab8eaa89539b66e47
16 spread1.dll 227ec327fe7544f04ce07023ebe816d5
17 spread2.dll 90a7f97c02d5f15801f7449cdf35cd2d
18 sys.dll 70dbbaba56a58775658d74cdddc56d05
19 webb.dll 8a3d2ae32b894624b090ff7a36da2db4
20 p2pR.dll e0061dce024cca457457d217c9905358

Sądząc po nazwach, Tofsee poza spamowaniem ma także inne funkcje, jak koordynowany DDoS, czy kopanie kryptowalut (jak się okazuje, jednym z pobieranych zasobów jest właśnie koparka Litecoinów).

Typ 11

Zawiera okresowo uaktualniane skrypty w nietypowym języku, których zadaniem jest rozsyłanie spamu. Przykładowy skrypt:

Język ma składnię delikatnie podobną do assemblera – na przykład „J” na początku linii oznacza „jump”, a „L” – zdefiniowanie etykiety (ang. label). Wewnątrz skryptu zawarte są także makra, które w trakcie wykonywania zamieniane są na inny tekst – przykładem może być %ATTNAME1.

Typ 7

Zawiera makra ogólnego przeznaczenia. Nazwa tych zasobów jest taka sama, jak makro, które opisują, np. %DATE_RAN_SUB (przypuszczalnie skrót od angielskiego „DATE RANDOM SUBJECT”). Zawartość zasobu to lista różnych podstawień oddzielonych znakami nowej linii. Przykładowa zawartość:

Ponieważ niektóre zmienne potrzebują skorzystać dosłownie ze znaku nowej linii, wprowadzone są także specjalne zmienne, jak %SYS_N służące właśnie do tego celu.

Typ 8

Zawiera makra lokalne. Ponieważ różne skrypty mogą chcieć korzystać ze zmiennych o tych samych nazwach, ale innej zawartości, niektóre makra są lokalne. Nazwy zasobów mają postać NUM%VAR, np. 1819%TO_NAME, gdzie 1819 to numer porządkowy skryptu będącego zakresem stosowania makra %TO_NAME.

Podstawienia zmiennych są rekurencyjne, co zresztą widać na wyżej wymienionym przykładzie %DATE_RAN_SUB – makra potrafią zawierać w swoim rozwinięciu inne makra. Ponadto język wspiera bardziej skomplikowane konstrukcje w rodzaju %RND_DIGIT[3], oznaczające trzy losowe cyfry (co jest często używane podczas generowania losowego koloru w postaci szesnastkowej), a także %{%RND_DEXL}{ %RND_SMILE}{}, oznaczający wybór jednego z %RND_DEXL, %RND_SMILE i pustego tekstu. Widać więc, że język jest dość elastyczny.

Reszta typów zawiera zaledwie pojedyncze zasoby i dlatego pominę ich opis w tym artykule.

Na zakończenie, załączam hash analizowanej próbki oraz reguły YARA pasujące do tej rodziny malware’u.

Hash:
ae0d32e51f36ce6e6e8c5ccdc3d253a0 - analizowana próbka (przed rozpakowaniem)

Reguły YARY: