Во второй и заключительно части этой серии статей мы обсудим принципы обнаружения Sebek, одной из самых распространенных утилит сбора данных, часто используемой администраторами электронных приманок. Затем мы рассмотрим другие методы обнаружения электронных приманок, а именно, способы специфичные для архитектуры x86 и принципы анализа на основе временных характеристик. Давайте начнем.
Во второй и заключительно части этой серии статей мы обсудим принципы обнаружения Sebek, одной из самых распространенных утилит сбора данных, часто используемой администраторами электронных приманок. Затем мы рассмотрим другие методы обнаружения электронных приманок, а именно, способы специфичные для архитектуры x86 и принципы анализа на основе временных характеристик. Давайте начнем.
Работа всех версий Sebek основана на подмене системного вызова read(). Таким образом, эта утилита может записывать все данные, к которым через вызов read() имел доступ хакер. Например, Sebek может контролировать логи SSH-сессий, восстанавливать файлы, скопированные с помощью SCP, а также перехватывать все пароли, используемые злоумышленниками. Собранные данные скрытно пересылаются с клиента на сервер Sebek. Скрытие от хакера исходящих пакетов достигается путем модификации сетевого стека ОС.
В одной из предыдущих статей мы показали, как можно обнаружить Sebek, анализируя информацию сетевого уровня OSI [3]. Теперь мы рассмотрим вопросы обнаружения Sebek на системном уровне. Сначала мы подробно рассмотрим Linux версии 2.1.7, а затем коснемся вопросов обнаружения Sebek и на других системах.Sebek скрывает свое присутствие в системе тем же способом, что и известный руткит adore: использует cleaner.c, простой подгружаемый модуль ядра, удаляющий ссылку на последний модуль в списке модулей ядра. Благодаря этому, программы типа lsmod не отображают наличие модуля Sebek в системе. Но в памяти все еще присутствует структура, описывающая заголовок “скрытого” модуля Sebek. Эта структура может быть найдена без особых усилий и может использоваться для поиска в памяти кода Sebek (например, функции cleanup_module()) и переменных. Утилита module_hunter.c [4] способна обнаруживать скрытые модули ядра. Она ищет по шаблону структуры заголовков модулей в адресном пространстве ядра и позволяет обнаруживать модули, скрытые вышеописанным способом:
# lsmod Module Size Used by Not tainted ds 7092 2 yenta_socket 10912 2 pcmcia_core 42912 0 [ds yenta_socket] ipsec 268100 0 usbcore 64972 1 # insmod module_hunter.o # cat /proc/showmodules # dmesg | tail -n 9 address module 0xe0e6d000 usbcore size: 0xfdcc 0xe0e7e000 snd-pcmcia size: 0x50b4 0xe0e86000 ipsec size: 0x41744 0xe0ec9000 module_hunter size: 0x3ec 0xe0f2e000 pcmcia_core size: 0xa7a0 0xe0f3a000 yenta_socket size: 0x2aa0 0xe0f44000 ds size: 0x1bb4Если вы сравните вывод lsmod с результатами работы module_hunter, вы увидите два отличия: новый, загруженный нами, модуль ядра с именем “module_hunter” и скрытый модуль "snd-pcmcia" не отображенный lsmod, но обнаруженный с помощью module_hunter.
Кроме того, используя эту методику, мы может определить адрес функции cleanup_module() модуля Sebek. Зная этот адрес, можно отключить этот элемент электронной приманки. Простой модуль ядра, совершающий переход на адрес расположения cleanup_module() в памяти и таким образом исполняющий эту функцию, выгружает Sebek из памяти. Данный прием работает благодаря тому, что Sebek перед выгрузкой восстанавливает указатель на оригинальный системный вызов read() (ord в представленном ниже фрагменте кода):
if(sct && ord){ sct[__NR_read] = (unsigned long *)ord; }Теперь, после вызова функции cleanup_module(), в таблице системных вызовов будет находиться оригинальный адрес read() и дальнейшее слежение за данными, переданными в эту функцию, прекратится.
Для обнаружения Sebek можно использовать приемы, применяемые при обнаружении руткитов. Анализируя адреса системных вызовов в таблице системных вызовов можно выявить факт ее модификации. В исходной таблице системных вызовов адреса функций read() и write() смежные. Так как Sebek изменяет указатель на системный вызов read(), условие смежности перестает выполняться. Таким образом, анализируя адреса этих двух системных вызовов можно определить, изменялась ли таблица системных вызовов. Пример этого показан ниже:
Исходная таблица системных вызовов:sys_read = 0xc0132ecc sys_write = 0xc0132fc8После загрузки Sebek:
sys_read = 0xc884e748 sys_write = 0xc0132fc8Обратите внимание на то, что системный вызов read() располагается в памяти очень далеко от write(), что может быть индикатором того, что кто-то изменил таблицу системных вызовов.
Для скрытия своего присутствия Sebek также модифицирует сетевой стек. Чтобы скрыть передачу собранной информации, производится корректировка некоторых счетчиков. Данная модификация также может быть обнаружена подготовленным атакующим, который может сравнить значения внутренних сетевых счетчиков ядра с выводом ifconfig или других подобных утилит.
В дополнение, обнаружив присутствие Sebek, можно получить некоторую полезную информацию из самого приложения, например IP адрес, на который отправляются собранные данные, и так называемое магическое число. Это осуществляется путем поиска в области памяти, выделенной Sebek, и применения некоторых эвристик. Короче говоря, производится эвристический поиск переменных, похожих на переменные конфигурации Sebek. Например, если в памяти Sebek найдено значение f001c0de, можно предположить, что возможно это магическое число. Это значение не может быть целевым IP адресом, так как f001c0de соответствует зарезервированному IP адресу 240.1.192.222 . Подобный эвристический анализ можно применить и к другим переменным, обнаруженным в памяти. Более подробно эта тема рассматривается в [5].Набор утилит, разработанный участниками немецкого проекта Honeynet в рамках проекта NoSEBrEaK [6], демонстрирует недостатки последней Linux-версии Sebek. Кроме реализации вышеупомянутых методов, этот набор включает утилиту Kebes, искусно использующую mmap() и не использующую системный вызов read(). Kebes реализует все основные возможности командного интерпретатора, включая чтение, запись и безопасное удаление файлов, выполнение программ и многое другое. Кроме этого, утилита создает шифруемый канал между атакующим и электронной приманкой, что делает бесполезными логи сетевой активности, так как администратор honeypot не обладает ключом для их расшифровки.
C:\>kproccheck -d KProcCheck Version 0.1 Proof-of-Concept by SIG^2 (www.security.org.sg) 80400000 - \WINNT\System32\ntoskrnl.exe 80062000 - \WINNT\System32\hal.dll F7410000 - \WINNT\System32\BOOTVID.DLL [...] F7298000 - SEBEK.sys [...]Другой способ обнаружения Sebek состоит в поиске подмененных API-функций, что похоже на определение факта модификации таблицы системных вызов в Linux. KProcCheck также может показать подмененные функции Native API:
C:\>kproccheck -t KProcCheck Version 0.1 Proof-of-Concept by SIG^2 (www.security.org.sg) Checks SDT for Hooked Native APIs ZwClose 18 SEBEK.sys [F729A092] ZwCreateFile 20 SEBEK.sys [F729A98C] ZwCreateKey 23 SEBEK.sys [F729AD10] ZwEnumerateKey 3C SEBEK.sys [F729AE02] ZwEnumerateValueKey 3D SEBEK.sys [F729AA50] ZwOpenFile 64 SEBEK.sys [F729A8E6] ZwOpenKey 67 SEBEK.sys [F729AD88] ZwQueryDirectoryFile 7D SEBEK.sys [F729A4CC] ZwQuerySystemInformation 97 SEBEK.sys [F729A5F0] ZwReadFile A1 SEBEK.sys [F7299CF0] ZwRequestWaitReplyPort B0 SEBEK.sys [F7299F14] ZwSecureConnectPort B8 SEBEK.sys [F7299FE6] ZwWriteFile ED SEBEK.sys [F7299D48] Number of Service Table entries hooked = 13
Методы обнаружения и отключения Sebek под Windows были разработаны Тэн Чью Конгом (Tan Chew Keong), опубликовавшим две статье по этой тематике [9].
# echo "disassemble dofileread" | gdb -q /bsd | grep sebek 0xd01c9bdc <dofileread+292>: call 0xd01c967c <sebeklog>Кроме того, обнаружить присутствие Sebek и получить о нем кое-какую информацию, можно сняв отпечатки (fingerprinting) bpf. Более подробно почитать о проблемах Sebek на OpenBSD можно в статье от Droids Corporation [10].
IDT (interrupt descriptor table - таблица дескрипторов прерываний) похожа на GDT и LDT, но содержит дескрипторы для обеспечения доступа к прерываниям и обработчикам исключений. IDT заменяет таблицу векторов прерываний, используемую в x86-системах.
Регистры GDTR, LDTR и IDTR содержат адреса и размеры соответствующих таблиц. Содержимое этих регистров может быть получено с помощью трех команд: SGDT, SIDT, и SLDT.Команда SGDT записывает содержимое регистра GDTR в 6-байтовую ячейку памяти. Команда SLDT записывает содержимое LDTR в 16 или 32-битный регистр общего назначения или ячейку памяти. Информация из регистра IDTR записывается в 6-байтовую ячейку памяти с помощью команды SIDT.
Обычно эти команды используются только операционными системами, хотя и не являются привилегированными на процессорах архитектуры x86. Это означает, что данные команды могут быть выполнены непривилегированным процессом, выполняющимся в режиме пользователя (ring 3). Так как процессор Intel архитектуры имеет по одному регистру LDTR, IDTR, и GDTR, при использовании одновременно нескольких ОС возникают проблемы (когда несколько систем пытаются работать с одними и теми же регистрами). Например, это может быть основная ОС и ОС, запущенная внутри виртуальной машины. В этом случае, чтобы избежать конфликта, основная ОС должна корректировать IDTR операционной системы, запущенной внутри виртуальной машины. Но процесс, выполняющийся внутри виртуальной машины, может получить значение регистра IDTR с помощью команды SIDT. Так как эта команда не требует повышенных привилегий и не генерирует исключение, основная ОС никак не может предотвратить ее выполнение. Но процесс, запущенный внутри виртуальной машины получает скорректированный адрес IDT, на основании чего может сделать вывод, что он выполняется внутри виртуального окружения.Подробная информация о проблемах виртуализации на x86 процессорах доступна по ссылкам ниже [11,12].
Метод, известный под название “execution path analysis” (EPA), основанный на подсчете исполненных команд, был описан Яном К. Рутковски (Jan K. Rutkowski) в Phrack [13]. В основе этого метода лежит подмена обработчика системных вызов (int 80) и обработчика отладочных исключений (int 1) в таблице дескрипторов прерываний (IDT). Затем, после установки TF-бита (0x100) в регистре EFLAGS, новые обработчики могут подсчитывать каждый SIGTRAP, генерирующийся после выполнения команды. Первоначально разработанный для Linux, этот метод был реализован и под Windows. Так как Windows защищает IDT, это было весьма не просто. Эдгар Барбоса (Edgar Barbosa) в свой недавней статье [14] демонстрирует способ противодействия EPA.
В статье из Phrack также обсуждается x86 команда rdtsc, являвшаяся решением проблемы Марсина Зиманека (Marcin Szymanek). Ян К. Рутковски утверждает, что из-за оптимизации в новых версиях компиляторов, измерение времени выполнения системного вызова с помощью rdtsc не точно. Однако, Дж. Делоллео (G. Delalleau), другой участник французского проекта Honeynet, решил исследовать этот вопрос [15], так как EPA имеет несколько недостатков:Способ, предложенный Делоллео, более точен за счет большего количества опытов, что дает более высокую статистическую точность. Перед использованием метода нужно собрать статистику времени выполнения на доверенных “чистых” хостах. Затем, при возникновении подозрения о наличии электронной приманки, нужно сравнить статистику, полученную на этой машине, со статистикой нормальных систем. Для сравнения Делоллео использует коэффициент, равный разнице преобразований Фурье от этих значений. Полученное значение будет близко к 1, в случае “чистого” хоста (т.е. статистика этой системы совпадет с предварительно собранной на обычной системе), и близко к 0 в обратном случае.
Этот способ неплохо работает при обнаружении подмененных руткитами функций и виртуальных машин, добавляющих несколько дополнительных шагов к нормальному процессу исполнения. Рассмотрим два примера:В настоящее время такие приманки могут использоваться, прежде всего, против неквалифицированных хакеров или “script kiddies”. Утилиты, которые они используют, не очень сложны, но достаточно эффективны. Мы можем поспорить, что скоро в эти утилиты будут внедрены технологии снятии отпечатков honeypot. Появление одной такой утилиты принесет выгоду тысячам неквалифицированным хакерам-новичкам.
В этой статье вы увидели, что во многих различных окружениях электронные приманки могут быть обнаружены. Значит ли это, что построение honeypot бесполезное занятие? Несколько лет назад сканирование портов было неотъемлемой частью большинства атак, что легко обнаруживалось межсетевым экраном. Потом оно превратилось в сканеры уязвимостей, действия которых можно было обнаружить любой системой обнаружения атак. Теперь, с помощью электронных приманок, определен новый главный инструмент хакера – автоматизированные утилиты, использующие всем известные уязвимости. Это говорит нам о том, что пришло время создавать электронные приманки нового поколения. Такие вещи развиваются быстро.Как говорил Дарвин, такова жизнь!