Linux Kernel Runtime Guard

Linux Kernel Runtime Guard (LKRG) — это модуль для ядра Linux, отвечающий за проверку целостности среды и предотвращающий выполнение эксплойтов, нацеленных на уязвимости в самом ядре.

Linux Kernel Runtime Guard LKRG

Linux Kernel Runtime Guard.

На сайте для загрузки (на момент написания заметки) уже доступна версия 0.1, проект в разработке, так что на прод его тащить не стоит конечно же, но любопытства и интереса ради, в тестовом окружении его уже можно использовать. Перед использованием LKRG нужно сразу же прояснить некоторые моменты:

  • LKRG — не волшебная таблетка и не панацея от всего. Тесты показали что например, попытки эксплуатации CVE-2017-5123 и CVE-2017-6074 были обнаружены, но в то же время, CVE-2016-5195 (Dirty COW) сработал и детектирован не был. Так что возможность использования эксплойтов, нацеленных на юзерспейс всё же остаётся.
  • В данный момент замечено, что использование LKRG может понизить производительность системы примерно на 6.5%. В этом ключе предстоит ещё много работы. На сколько такая просадка окажется критичной, каждый решает для себя сам. Думаю что для тестовых стендов это не такое уж и страшное число.

Из положительного у нас есть вот что:

  • Непосредственно защита ядра от атак на него нацеленных. Потенциально — защита в том числе и от неизвестных пока что эксплойтов (целенаправленно не пытающихся LKRG обойти).
  • Поддержка популярных операционных систем. Заявлены в данный момент RHEL7, Ubuntu 16.04 и даже OpenVZ 7, Virtuozzo 7.
  • Простота установки и использования. LKRG собирется и ставится как модуль ядра, а не патч, что значительно упрощает работу с ним.

Установка и запуск LKRG.

1. Не является обязательным требованием, но для меня выглядит вполне логичным — обновляем ядро до последней актуальной версии доступной в репозиториях, запускаем сервер в работу с ним.

2. Для сборки потребуются make и C компилятор. Кроме того, ставим в систему -devel пакеты ядра (команда в зависимости от ОС):

# yum install kernel-devel
$ sudo apt-get install linux-headers-$(uname -r)

3. Собираем сам модуль. Его можно либо скачать в архиве, либо забрать c Github’а (сделаем так):

# cd /usr/local/src/
# git clone https://bitbucket.org/Adam_pi3/lkrg-main.git
# cd lkrg-main/
# make -j8

4. И запускаем его в работу как и любой другой модуль ядра:

# insmod output/p_lkrg.ko p_init_log_level=3

В системном логе, при этом, осядет следующая информация:

Feb 9 08:39:49 pm kernel: p_lkrg: loading out-of-tree module taints kernel.
Feb 9 08:39:49 pm kernel: p_lkrg: module verification failed: signature and/or required key missing - tainting kernel
Feb 9 08:39:49 pm kernel: [p_lkrg] Loading LKRG...
Feb 9 08:39:49 pm kernel: [p_lkrg] LKRG initialized successfully!
Feb 9 08:40:04 pm kernel: [p_lkrg] System is clean!
Feb 9 08:40:19 pm kernel: [p_lkrg] System is clean!

Теперь, с учётом настроенного log level, система будет сообщать в лог о том, что с ней всё в порядке сообщением «System is clean!»

Настройки для LKRG.

С загрузкой модуля, в sysctl у нас появляются несколько параметров, которыми мы можем управлять:

# sysctl -a | grep lkrg
lkrg.block_modules = 0
lkrg.clean_message = 1
lkrg.force_run = 0
lkrg.hide = 0
lkrg.log_level = 3
lkrg.timestamp = 15

lkrg.block_modules — блокировать (1), или не блокировать (0) загрузку модулей в ядро.
lkrg.clean_message — выводить ли сообщение «System is clean», если значение log_level позволяет это делать.
lkrg.force_run — при передаче сюда единицы, будет произведён запуск проверки целостности. Функция проверки будет запущена, при этом, значение будет вновь изменено на 0.
lkrg.log_level — уровень детализации логов, которые ведёт LKRG.
lkrg.timestamp — частота вызова функции целостности в секундах. Сюда можно передать значение от 5 до 1800.
lkrg.hide — механизм сокрытия модуля в системе. О нём немного подробнее ниже.

Скрываем LKRG.

С помощью параметра lkrg.hide мы можем скрыть присутствие модуля в системе, выглядит это так:

# lsmod | grep lkrg
p_lkrg 122402 0 
# sysctl lkrg.hide=1
lkrg.hide = 1
# lsmod | grep lkrg
#
# sysctl lkrg.hide=0
lkrg.hide = 0
# lsmod | grep lkrg
p_lkrg 122402 -2 
#

Важный момент здесь — допустим модуль был скрыт, а нам потребовалось выгрузить его. Перед выгрузкой необходимо сделать unhide, а затем уже отключить сам модуль с опцией —force:

# sysctl lkrg.hide=0
lkrg.hide = 0
# lsmod | grep lkrg
p_lkrg 122402 -2 
# rmmod --force p_lkrg

О загрузке, выгрузке модуля в логе будут оставаться соответствующие сообщения:

Feb 9 09:42:10 pm kernel: [p_lkrg] Unloading LKRG...
Feb 9 09:42:10 pm kernel: [p_lkrg] LKRG unloaded!
Feb 9 09:42:20 pm kernel: [p_lkrg] Loading LKRG...
Feb 9 09:42:20 pm kernel: [p_lkrg] LKRG initialized successfully!

Обнаружение эксплойта.

О попытках применения эксплойтов, ядро нам так же будет сообщать, например вот так:

Feb 9 10:09:38 tst kernel: traps: p_write8[20820] general protection ip:400dd0 sp:7f018cc05f00 error:0 in p_write8[400000+2000]
Feb 9 10:09:38 tst kernel: [1026127.772356] [p_lkrg] <Exploit Detection> process[19633 | procrop] has different UID! [504 vs 0 :(
Feb 9 10:09:38 tst kernel: [1026127.772365] [p_lkrg] <Exploit Detection> process[19633 | procrop] has different EUID! [504 vs 0 :(
Feb 9 10:09:38 tst kernel: [1026127.772368] [p_lkrg] <Exploit Detection> process[19633 | procrop] has different SUID! [504 vs 0 :(
Feb 9 10:09:38 tst kernel: [1026127.772370] [p_lkrg] <Exploit Detection> process[19633 | procrop] has different FSUID! [504 vs 0 :(
Feb 9 10:09:38 tst kernel: [1026127.772372] [p_lkrg] <Exploit Detection> process[19633 | procrop] has different GID! [504 vs 0 :(
Feb 9 10:09:38 tst kernel: [1026127.772374] [p_lkrg] <Exploit Detection> process[19633 | procrop] has different EGID! [504 vs 0 :(
Feb 9 10:09:38 tst kernel: [1026127.772376] [p_lkrg] <Exploit Detection> process[19633 | procrop] has different SGID! [504 vs 0 :(
Feb 9 10:09:38 tst kernel: [1026127.772378] [p_lkrg] <Exploit Detection> process[19633 | procrop] has different FSGID! [504 vs 0 :(
Feb 9 10:09:38 tst kernel: [1026127.772380] [p_lkrg] <Exploit Detection> Trying to kill process[procrop | 19633]!19633

Кроме того, если система была скомпрометирована до загрузки модуля и это будет обнаружено, при запуске LKRG сообщит об этом.

Промежуточный итог.

На этом, пока что, можно остановиться. Что в итоге? Linux Kernel Runtime Guard оставляю работать на одном из своих серверов, где размещены несколько сайтов и сервисов. Посмотрим как он покажет себя в дальнейшем, ну и за самим проектом, конечно же буду следить, а по возможности пополнять заметку дополнительным материалом.

@SysadminNotes | https://sysadmin.pm

One thought on “Linux Kernel Runtime Guard

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *