Противодействие Honeypots: Системные вопросы, часть вторая

Противодействие Honeypots: Системные вопросы, часть вторая

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

 Торстен Хольц и Фредерик Рейнел, перевод Владимир Куксенок

Введение

В этой статье описывается, как обычно происходит атака на электронную приманку (honeypot). В первой части мы обратили внимание на сходство электронных приманок со стеганографией и рассмотрели три основных способа построения виртуального honeypot. Для каждого из этих способов, а именно, User Mode Linux, VMware и chroot/jail, мы описали недостатки, приводящие к обнаружению электронной приманки. Было показано, что, несмотря на отдельные преимущества каждого из решений, все они могут быть легко обнаружены опытным хакером.

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

Обнаружение Sebek

Sebek [1,2] очень часто используется для сбора информации об активности атакующего на электронной приманке. Это клиент-серверное приложение, доступное под различными ОС, включая Linux, Windows и *BSD.

Работа всех версий Sebek основана на подмене системного вызова read(). Таким образом, эта утилита может записывать все данные, к которым через вызов read() имел доступ хакер. Например, Sebek может контролировать логи SSH-сессий, восстанавливать файлы, скопированные с помощью SCP, а также перехватывать все пароли, используемые злоумышленниками. Собранные данные скрытно пересылаются с клиента на сервер Sebek. Скрытие от хакера исходящих пакетов достигается путем модификации сетевого стека ОС.

В одной из предыдущих статей мы показали, как можно обнаружить Sebek, анализируя информацию сетевого уровня OSI [3]. Теперь мы рассмотрим вопросы обнаружения Sebek на системном уровне. Сначала мы подробно рассмотрим Linux версии 2.1.7, а затем коснемся вопросов обнаружения Sebek и на других системах.

Обнаружение Sebek на Linux

Linux-версия Sebek это модуль ядра, работающий по принципу руткита. Он перезаписывает указатель на системный вызов read() в таблице системных вызовов на свою реализацию этой функции. Это позволяет контролировать все данные, переданные в функцию read().

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 не обладает ключом для их расшифровки.

Обнаружение Sebek на других операционных системах

Подобными способами можно обнаружить присутствие Sebek и на других ОС. Для начала рассмотрим версию для Windows. Sebek под Windows это драйвер ядра, для сбора данных подменяющий собой все консольные и GUI операции read(). Используя функцию PsLoadedModuleList, можно обнаружить “скрытый” драйвер ядра. Это похоже на поиск в памяти “скрытых” модулей в ОС Linux. С помощью утилит, подобных KProcCheck [7] можно обнаружить Sebek в Windows:
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

Отключить Sebek можно и в Windows. ОС Windows хранит полную копию SDT ServiceTable в файле ядра ntoskrnl.exe, и, используя SDTRestore, можно восстановить SDT ServiceTable [8]. И снова это напоминает восстановление таблицы системных вызовов в Linux.

Методы обнаружения и отключения Sebek под Windows были разработаны Тэн Чью Конгом (Tan Chew Keong), опубликовавшим две статье по этой тематике [9].

Sebek на OpenBSD

В качестве последнего примера давайте рассмотрим OpenBSD-версию Sebek. Sebek для OpenBSD это патч для ядра, повторяющий функциональность других версий. Все данные, проходящие через системный вызов read(), записываются и скрытно передаются на доверенный хост. Но, тем не менее, Sebek может быть обнаружен атакующим. Дизассемблировав функцию “dofileread" ядра ОС можно обнаружить присутствие Sebek:
# echo "disassemble dofileread" | gdb -q /bsd | grep sebek
0xd01c9bdc <dofileread+292>:    call   0xd01c967c <sebeklog>
Кроме того, обнаружить присутствие Sebek и получить о нем кое-какую информацию, можно сняв отпечатки (fingerprinting) bpf. Более подробно почитать о проблемах Sebek на OpenBSD можно в статье от Droids Corporation [10].

Другие методы обнаружения электронных приманок

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

Особенности архитектуры процессора

Один из способов обнаружения виртуальной машины специфичен только для процессоров архитектуры x86. В защищенном режиме все операции доступа к памяти проходят через GDT (global descriptor table – глобальная таблица дескрипторов) или LDT (local descriptor table - локальная таблица дескрипторов). GDT и LDT содержат дескрипторы сегментов, описывающие базовый адрес, права доступа, размер и дополнительную информацию для каждого сегмента. GDT используется всеми программами, тогда как LDT может быть произвольно определена для конкретных приложений с целью расширения адресного пространства.

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].

Временные характеристики

Лучшие honeypot-решения обычно предполагают наличие качественной системы слежения и использование виртуальной машины. Это очень важные свойства, однако… Каждое действие на honeypot занимает больше времени, чем на обычной системе, в следствии того, что:
  • Из-за эмулирования или ведения логов выполняется больше команд процессора.
  • Так как для выполнения команды в виртуальной машине в реальности нужно выполнить несколько команд процессора, на это требуется больше времени.
Следовательно, обладая методами подсчета количества выполненных команд или времени их выполнения, можно эффективно обнаруживать honeypot-окружения.

Метод, известный под название “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 имеет несколько недостатков:
  • Необходимость высоких привилегий в системе (права root’a и доступ к адресному пространству ядра).
  • Модификацию системных вызовов не так просто скрыть: измененный адрес обработчика int 1 может свидетельствовать об установке бита TF.
Делоллео предложил способ обнаружения изменений во времени выполнения, основанный на специфичных регистрах и командах процессора (таких как rdtsc в x86). Однако здесь присутствует известная проблема существенного различия измерений в зависимости от переключения контекста, IRQ и других вещей. Первым делом нужно исследовать среднее или минимальное время выполнения. Обратите внимание, ниже мы продолжим использовать термин “время”, но фактически будем подсчитывать такты.

Способ, предложенный Делоллео, более точен за счет большего количества опытов, что дает более высокую статистическую точность. Перед использованием метода нужно собрать статистику времени выполнения на доверенных “чистых” хостах. Затем, при возникновении подозрения о наличии электронной приманки, нужно сравнить статистику, полученную на этой машине, со статистикой нормальных систем. Для сравнения Делоллео использует коэффициент, равный разнице преобразований Фурье от этих значений. Полученное значение будет близко к 1, в случае “чистого” хоста (т.е. статистика этой системы совпадет с предварительно собранной на обычной системе), и близко к 0 в обратном случае.

Этот способ неплохо работает при обнаружении подмененных руткитами функций и виртуальных машин, добавляющих несколько дополнительных шагов к нормальному процессу исполнения. Рассмотрим два примера:
  1. Можно обнаружить присутствие Sebek по времени выполнения системного вызова read(). На системе без Sebek минимальное время выполнения около 8225, а вышеупомянутый коэффициент равен 0.776282. На системе с установленным Sebek минимальное время выполнения - 29999, коэффициент - 0.009930. Такое различие имеет место быть вследствие того, что каждый вызов read() на системе с Sebek, сопровождается посылкой как минимум одного UDP пакета.
  2. Обнаружить VMware также очень просто при попытке выполнения неверных команд. Метод основывается на том, что обработчик исключений VMware, в случае неверной команды, должен проверять, нужно ли обработать исключение средствами VMware или исключение будет обработано самим исполняемым процессом. Время обработки неверной команды 776mms на нормальной системе и 2530mms на VMWare.
Утилита ktime доступна и может быть получена от Gael.

Итоги

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

Заключение

Существует два способа построения электронной приманки с высоким уровнем контроля: использование виртуальной машины или улучшение механизмов слежения существующей системы.

В настоящее время такие приманки могут использоваться, прежде всего, против неквалифицированных хакеров или “script kiddies”. Утилиты, которые они используют, не очень сложны, но достаточно эффективны. Мы можем поспорить, что скоро в эти утилиты будут внедрены технологии снятии отпечатков honeypot. Появление одной такой утилиты принесет выгоду тысячам неквалифицированным хакерам-новичкам.

В этой статье вы увидели, что во многих различных окружениях электронные приманки могут быть обнаружены. Значит ли это, что построение honeypot бесполезное занятие? Несколько лет назад сканирование портов было неотъемлемой частью большинства атак, что легко обнаруживалось межсетевым экраном. Потом оно превратилось в сканеры уязвимостей, действия которых можно было обнаружить любой системой обнаружения атак. Теперь, с помощью электронных приманок, определен новый главный инструмент хакера – автоматизированные утилиты, использующие всем известные уязвимости. Это говорит нам о том, что пришло время создавать электронные приманки нового поколения. Такие вещи развиваются быстро.

Как говорил Дарвин, такова жизнь!

Ссылки

  1. Sebek, by Edward Balas et al.
    http://www.honeynet.org/tools/sebek/
  2. Know Your Enemy: Sebek
    http://www.honeynet.org/papers/sebek.pdf
  3. Противодействие Honeypots: Сетевые вопросы, Части 1 и 2
    http://www.securitylab.ru/analytics/216374.php
    http://www.securitylab.ru/analytics/216386.php
  4. Finding hidden kernel modules (the extrem way), by madsy
    http://www.phrack.org/show.php?p=61&a=3
  5. Attacking Honeynets, by Maximillian Dornseif, Thorsten Holz, and Christian Klein
    http://www-i4.informatik.rwth-aachen.de/lufg/research/projects/honeynet/material/NoSEBrEaK-IAW.pdf
  6. NoSEBrEaK Project, Kebes toolkit
    http://md.hudora.de/presentations/#nosebreak
  7. KProcCheck
    Win2K Kernel Hidden Process/Module Checker, by Tan Chew Keong
    http://www.security.org.sg/code/kproccheck.html
  8. SDT Restore for Win2K/XP, by Tan Chew Keong
    http://www.security.org.sg/code/sdtrestore.html
  9. Detecting Sebek Win32 Clients, by Tan Chew Keong
    http://www.security.org.sg/vuln/sebek215.html
    http://www.security.org.sg/vuln/sebek215-2.html
  10. Sebek2 client for OpenBSD, by Droids Corporation
    http://honeynet.droids-corp.org/download/sebek-openbsd.pdf
  11. Analysis of the Intel Pentium's Ability to Support a Secure Virtual Machine Monitor
    http://www.cs.nps.navy.mil/people/faculty/irvine/publications/2000/VMM-usenix00-0611.pdf
  12. Red Pill... or how to detect VMM using (almost) one CPU instruction, by Joanna Rutkowska
    http://invisiblethings.org/papers/redpill.html
  13. Execution path analysis: finding kernel based rootkits, by J.K. Rutkowski
    http://www.phrack.org/show.php?p=59&mp;a=10
  14. Avoiding Windows Rootkit Detection, Edgar Barbosa, 2004.
    http://www.rootkit.com/vault/Opc0de/bypassEPA.pdf
  15. Mesure locale des temps d'ex?cution: application au contr?le d'int?grit? et au fingerprinting, by G. Delalleau
    SSTIC 2004 - http://actes.sstic.org/SSTIC04/Fingerprinting_integrite_par_timing/

Ваша приватность умирает красиво, но мы можем спасти её.

Присоединяйтесь к нам!