Контролируем и ограничиваем системные вызовы с помощью systrace::Журнал СА 8.2005
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
О журнале
Журнал «БИТ»
Наука и технологии
Подписка
Где купить
Авторам
Рекламодателям
Магазин
Архив номеров
Вакансии
Контакты
   

  Опросы

Какие курсы вы бы выбрали для себя?  

Очные
Онлайновые
Платные
Бесплатные
Я и так все знаю

 Читать далее...

1001 и 1 книга  
20.12.2019г.
Просмотров: 2978
Комментарии: 0
Dr.Web: всё под контролем

 Читать далее...

04.12.2019г.
Просмотров: 3641
Комментарии: 0
Особенности сертификаций по этичному хакингу

 Читать далее...

28.05.2019г.
Просмотров: 5855
Комментарии: 2
Анализ вредоносных программ

 Читать далее...

28.05.2019г.
Просмотров: 6261
Комментарии: 1
Микросервисы и контейнеры Docker

 Читать далее...

28.05.2019г.
Просмотров: 5467
Комментарии: 0
Django 2 в примерах

 Читать далее...

Друзья сайта  

Форум системных администраторов  

sysadmins.ru

 Контролируем и ограничиваем системные вызовы с помощью systrace

Архив номеров / 2005 / Выпуск №8 (33) / Контролируем и ограничиваем системные вызовы с помощью systrace

Рубрика: Безопасность /  Механизмы защиты

АЛЕКСАНДР БАЙРАК

Контролируем и ограничиваем системные вызовы с помощью systrace

Наверняка вы не раз задумывались о том, как именно работает та или иная используемая вами программа. Разобраться помогут исходные текcты программы. Но что делать, если они недоступны? Как всегда быть в курсе того, что происходит у вас в системе?

Systrace – инструмент для ограничения и контроля системных вызовов. Изначально systrace был написан для NetBSD, позже был портирован под OpenBSD, а в настоящий момент ведутся работы по переносу на Linux, FreeBSD и OpenDarwin.

Любая программа в процессе свой работы использует системные вызовы. Что такое системный вызов? Его можно определить как некую функцию, которая позволяет вашей программе обращаться к ядру ОС для выполнения некого действия. В современных версиях UNIX-систем реализовано около 300 различных системных вызовов. И если такие инструменты, как ktrace (kernel process tracing) и truss (tracing system call), позволяют нам выступать лишь в качестве наблюдателей, systrace позволяет нам вмешиваться в происходящее.

Пример использования

Перейдем к практике. В качестве примера напишем простую программу:

#include <stdio.h>

void proc1();

int main()

{

printf("just a message\n");

mkdir(«test»);

proc1();

}

void proc1()

{

printf("just a dumb procedure\n");

}

Как ясно из исходного текста, наша подопытная программа выполняет следующие действия:

  • Выводит на экран сообщение.
  • Создает каталог «test».
  • Передает управление процедуре «proc1».
  • Процедура proc1 выводит на экран сообщение.

Скомпилируем программу:

#gcc -o proga proga.c

На первый взгляд при выполнении нашей программы используются два системных вызова: mkdir и write. Хотя логично предположить, что, перед тем как «что-то» «куда-то» записать с помощью write, это самое «куда-то» нужно сначала открыть, а после записи закрыть, а значит, задействованы системные вызовы open и close . Также не лишено смысла предположение, что используется еще один системный вызов – exit. Итого пять вызовов. Посмотрим, как обстоят дела на самом деле:

#systrace -A /path/to/program/proga

Ключ -A указывает systrace автоматически создать политику для указанного исполняемого файла.

Автоматический режим предполагает создание правил в режиме «разрешить все».

После выполнения команды в домашнем каталоге пользователя появится подкаталог .systrace, в который будет помещен файл c правилами. Рассмотрим его:

Policy: /home/01mer/labs/systr/proga, Emulation: netbsd

    netbsd-mmap: permit

    netbsd-fsread: filename eq “/etc/ld.so.conf” then permit

    netbsd-__fstat13: permit

    netbsd-close: permit

    netbsd-munmap: permit

    netbsd-fsread: filename eq “/lib/libc.so.12.114.1” then permit

    netbsd-__sysctl: permit

    netbsd-fsread: filename eq “/etc/mallic.conf” then permit

    netbsd-break: permit

    netbsd-ioctl: permit

    netbsd-write: permit

    netbsd-fswrite: filename eq “/home/01mer/labs/systr/test” then permit

    netbsd-exit: permit

Синтаксис правил достаточно прост:

[системный вызов] [условие] [действие]

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

Рассмотрим полученные правила.

Policy: /home/01mer/labs/systr/proga, Emulation: netbsd

Указывается, для какого бинарного файла политика описана ниже. Полный путь к исполняемому файлу нужен для того, чтобы исключить возможность применения политики для файла с таким же именем, но располагающимся в другом месте. Emulation: netbsd показывает, что будет использоваться ABI ОС NetBSD.

    netbsd-mmap: permit

Как видно из названия, системному вызову mmap разрешено исполняться. Для позволения выполнения системного вызова используется действие – permit, для запрещения deny.

    netbsd-fsread: filename eq “/etc/ld.so.conf” then permit

Тут мы видим, что системному вызову fsread будет разрешено выполниться в том случае, если запрошенный им файл будет /etc/ld.so.conf. Стоп, скажет внимательный читатель, системного вызова fsread не существует! И будет абсолютно прав. По умолчанию в systrace применяется использование псевдонимов для системных вызовов. Например: fsread является псевдонимом для stat, lstat, readlink, access, open. Но при желании режим использования псевдонимов можно отключить. В дальнейшем комментировании всего файла конфигурации смысла не вижу – все должно быть понятно и без этого.

Что ж, политика для нашей программы создана, давайте попробуем ее выполнить под чутким руководством systrace:

#systrace -a /home/01mer/labs/systr/proga

just a message

just a dumb procedure

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

#objdump -d proga > proga.lst

Программа objdump показывает информацию из бинарных/объектных файлов. Ключ -d указывает, что файл нужно дисассемблировать. Вывод информации для удобства произведем в proga.lst

В полученном листинге находим нашу процедуру proc1.

08048833 :

 8048833:      55                          push   %ebp

 8048834:      89 e5                      mov    %esp,%ebp

 8048836:      83 ec 08                   sub    $0x8,%esp

 8048839:      83 ec 0c                   sub    $0xc,%esp

 804883c:      68 16 89 04 08             push   $0x8048916

 8048841:      e8 52 fc ff ff             call   8048498

 8048846:      83 c4 10                   add    $0x10,%esp

 8048849:      c9                                     leave 

 804884a:      c3                            ret   

 804884b:      90                          nop

Если не вдаваться в подробности, мы видим тут «подготовку» стека, выполнение вывода на экран текста, очищение стека и возврат в «основную» программу. Итого 25 байт, которые мы должны изменить на что то свое. Негусто, но вполне хватит для классического shell-кода вызывающего /bin/sh, он занимает как раз 23 байта (не забывайте, что 2 байта нам нужны для возврата в «основную программу»). А это именно то, что нам нужно – используется системный вызов, описания которого нет в наших правилах. Читаем man 2 execve. Для запуска /bin/sh через execve мы должны написать следующие:

execve("/bin/sh/",0,0);

Что можно свести к следующему коду на ассемблере:

xorl  %eax,%eax

pushl %eax

pushl $0x68732f2f

pushl $0x6e69622f

movl  %esp,%ebx

pushl %eax

pushl %esp

pushl %ebx

pushl %eax  

movb  $0x3b,%al

int   $0x80

Все это можно представить в следующих опкодах:

31 c0

50

68 6e 2f 73 68

68 2f 2f 62 69

89 e3

50

54

53

50

b0 3b

cd 80

Вооружившись hex-редактором, открываем исполняемый файл с нашей программой и меняем содержимое proc1 на представленные выше опкоды. Само собой, нам нужно оставить команды возврата в «основную» программу. После успешного редактирования проверяем результат:

# home/01mer/labs/systr/proga

Just a message

#

Как вы видите, вместо вывода на экран «just a dumb procedure» у нас запустился /bin/sh.

А теперь попробуем выполнить то же самое, но уже под контролем systrace:

# systrace -a /home/01mer/labs/systr/proga

Just a message

Jul 11 16:53:25 darkthrone.net1 systrace: deny user: 01mer, prog:

/home/01mer/labs/systr/proga, pid: 395(0)[0], policy:

/home/01mer/labs/systr/proga, filters: 13, syscall: netbsd-execve(59),

filename: /bin/sh, argv:

#

Как мы видим, попытка запустить модифицированную программу провалилась.

Автоматизируем создание правил

Доверить автоматическое создание правил systrace допустимо только в том случае, когда есть уверенность на 99,9% в том, что мы запускаем. Во всех остальных случаях рекомендуется создавать правила в интерактивном режиме. Рассмотрим пример:

# systrace -t  /home/01mer/labs/systr/newproga

Ключ -t указывает, чтобы интерактивное создание правил проходило в текстовом режиме. Если у вас на машине установлены x-windows, вы можете воспользоваться xsystrace.

/home/01mer/labs/systr/newproga, pid: 729(0)[0], policy:

/home/01mer/labs/systr/newproga, filters: 0, syscall: netbsd-mmap(197), args: 32

Answer:

Тут systrace ожидает от нас ввода permit, в случае если мы желаем разрешить системный вызов или deny для запрета. Конечно, интерактивное создание правил – процесс достаточно трудоемкий и занимает много времени, но полученный результат того стоит. Вы будете точно знать, когда и какие системные вызовы использует программа.

Дополнительные «полезности»

В синтаксисе правил вы можете использовать необязательные опции протоколирования.

Например:

netbsd-fsread: filename eq "/lib/libc.so.12.114.1" then permit log

параметр log указывает systrace протоколировать каждое обращение к указанному фильтру.

По умолчанию протоколируются лишь попытки выполнить системные вызовы, о которых нет ни слова в правилах. Для протоколирования systrace использует syslogd. А это значит, что мы можем немного поправить /etc/syslog.conf, чтобы все сообщения от systrace размещались в отдельном файле.

При желании даже можно написать маленький парсер для получаемых логов. Но это уже по желанию, все в ваших руках.

Нельзя не отметить еще одну необязательную опцию – errorcode. С её помощью мы можем указать, какая ошибка будет возвращаться при обращении к запрещенному системному вызову.

Например:

netbsd-fswrite: filename eq "/some/where/file" then deny[EIO]

В данном случае при попытке записи в файл системному вызову будет возвращена ошибка – input/outpu error. Для ознакомления с полным списком errno-кодов возврата вы можете прочитать man errno.

Заключение

Мы рассмотрели простой пример использования systrace. Изложенных сведений вам будет достаточно и для создания более сложных собственных правил для различных программ. Применение политик ограничения системных вызовов для конкретных программ поможет вам существенно повысить степень защиты ОС в целом.


Комментарии отсутствуют

Добавить комментарий

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

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-41
Fax: (499) 277-12-45
E-mail: sa@samag.ru