Методика выявления поверхности атаки

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

Ниже рассматривается проведение архитектурного анализа с применением инструмента «Natch». Этот инструмент в процессе выполнения тестового сценария работы системы с помощью отслеживания помеченных данных: автоматически выявляет процессы, модули и функции, которые непосредственно связаны с обработкой данных из недоверенных источников.

Инструмент основан на полносистемном эмуляторе QEMU. Для запуска анализируемого ядра в QEMU и выполнения в эмулируемом устройстве тестового сценария необходимо подготовить сжатый образ ядра (bzImage) и образ корневой файловой системы ОС, которая будет использоваться для выполнения тестового сценария (rootfs). Для проведения анализа необходимо подготовить несжатый образ анализируемого ядра (vmlinux) с файлом с символьной таблицей адресов функций образа ядра (System.map).

Для выполнения получения результатов автоматического анализа необходимо:

  • сконфигурировать «Natch»,
  • для настройки интроспекции выполнить предварительный запуск инструмента, запустив виртуальную машину с анализируемым ядром в QEMU с подключением соответствующих плагинов «Natch»,
  • записать снапшнот с выполнением в виртуальной машине тестового сценария,
  • запустить воспроизведение записанного снапшота с подключением плагинов «Natch» для выполнения автоматического анализа.

Далее применение «Natch» рассматривается на примере получения данных об обработке сетевых пакетов в ядре в процессе выполнения логина в виртуальную машину по SSH с авторизацией по ключу.

«Natch» на вход получает два конфигурационных файла. Файл natch.cfg - основной конфигурационный файл, отвечающий за общие настройки, и вспомогательный файл kernel_linux.cfg. Рассмотрим листинг конфигурации каждого файла.

Конфигурационный файл natch.cfg состоит из нескольких секций.

# [Ports]
# in=22
# out=22
[Taint]
threshold=250
on=true
[Modules]
config=kernel_linux.cfg
log=ssh_login_taint.log
[Tasks]
config=ssh_login_task.ini
file=ssh_login_procs.log
[Netlog]
log=ssh_login_net.log
tlog=ssh_login_tnet.log

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

Секция Taint содержит поля threshold и on. Первое из них — пороговое значение, заданное десятеричным числом в диапазоне от 0 до 255, чем меньше это число, тем больший объем данных будет отслеживаться. Второе — булевская переменная, в случае установки значения которой в true отслеживание недоверенных данных включается автоматически с самого начала работы эмулятора.

Секция Modules содержит поле config, где задано имя вспомогательного конфигурационного файла kernel_linux.cfg. В поле log задано имя файла ssh_login_taint.log, куда будет записан лог обращений к отслеживаемым данным.

Секция Tasks содержит поле config с именем файла со смещениями, который будет сформирован в результате предварительного запуска инструмента для настройки интроспекции.

Секция NetLog содержит поля log и tlog c именами файлов, в которые будет осуществляться запись логов с отслеженными сетевыми пакетами и с трассой вызовов функций, которые обрабатывали эти сетевые пакеты, соответственно.

В конфигурационном файле kernel_linux.cfg в секциях с префиксом Image описывается каждый отдельный бинарный модуль, из которых будет подгружаться символьная информация для определения имен вызываемых функций.

[Image]
# Полный путь до файла с бинарным образом ядра
path=/home/user/путь/к/файлу/vmlinux
# Полный путь до файла с символьной информацией, сгенерированной компилятором при сборке ядра
map=/home/user/путь/к/файлу/System.map
# Адрес начала секции .text
textstart=0xffffffff81000000

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

«Natch» представляет собой набор плагинов для эмулятора QEMU. Строка запуска состоит из конкатенации базовых опции командной строки эмулятора QEMU и дополнительных опций, необходимых для работы инструмента. Список дополнительных опции командной строки представлен ниже:

-os-version Linux
-plugin 

Опция os-version настраивает плагины для работы с операционной системой Linux. Опция plugin непосредственно подключает необходимые плагины.

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

$QEMU_PATH/qemu-img create -f qcow2 -b $ROOTFS_PATH/debian.img -F raw $ROOTFS_PATH/debian.diff

$QEMU_PATH - полный путь к каталогу с бинарными файлами сборки QEMU с поддержкой плагинов «Natch».

$ROOTFS_PATH - полный путь к каталогу с образом корневой файловой системы, сформированной при помощи инструмента debbootstrap, и с установленным пакетом opennsh.

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

Для предварительной настройки необходимо выполнить следующую команду:

$QEMU_PATH/qemu-system-x86_64 -m 8G -monitor stdio -kernel $KERNEL_PATH/bzImage \
-append "root=/dev/sda net.ifnames=0" -drive file=$ROOTFS_PATH/debian.img,format=raw \
-netdev user,id=net0 -device e1000,netdev=net0 \
-os-version Linux -plugin natch,config=natch.cfg,task_graph

$KERNEL_PATH - полный путь к каталогу с сжатым образом анализируемого ядра.

В результате запустится виртуальная машина, которая автоматически выключиться после завершения настройки.

Для записи выполнения тестового сценария необходимо выполнить следующие действия.

В командной строке терминала запустить эмулятор со следующими опциями:

$QEMU_PATH/qemu-system-x86_64 -m 8G -monitor stdio -os-version Linux -kernel $KERNEL_PATH/bzImage \
-append "root=/dev/sda net.ifnames=0" -drive file=$ROOTFS_PATH/debian.diff,if=none,id=disk \
-drive driver=blkreplay,if=none,image=disk,id=disk-rr -device ide-hd,drive=disk-rr \
-icount shift=1,rr=record,rrfile=ssh_login.bin,rrsnapshot=init \
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:10021-:22 \
-device e1000,netdev=net0 -object filter-replay,id=replay,netdev=net0 \
-plugin natch,config=natch.cfg,net_log

После загрузки операционной системы виртуальной машины, чтобы минимизировать время на воспроизведение записанного выполнения тестового сценария, непосредственно перед началом его выполнения в командной строке эмулятора QEMU выполняется команда старта записи снапшота:

(qemu) savevm ssh_login

Из другого терминала выполнить команду:

ssh -i $SSHKEY -p 10021 root@127.0.0.1

# SSHKEY — полный путь к файлу с приватным ключом, парный к которому
# публичный ключ загружен в образ корневой файловой системы.

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

(qemu) quit

Воспроизведения тестового сценария с отслеживанием данных необходимо выполнить команду:

$QEMU_PATH/qemu-system-x86_64 -m 8G -monitor stdio -os-version Linux -kernel $KERNEL_PATH/bzImage \
-append "root=/dev/sda net.ifnames=0" -drive file=$ROOTFS_PATH/debian.diff,if=none,id=disk \
-drive driver=blkreplay,if=none,image=disk,id=disk-rr -device ide-hd,drive=disk-rr \
-icount shift=1,rr=replay,rrfile=ssh_login.bin,rrsnapshot=ssh_login \
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:10021-:22 \
-device e1000,netdev=net0 -object filter-replay,id=replay,netdev=net0 \
-plugin natch,config=natch.cfg,task_graph

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

Информация о составе модулей и функций, которые обращались к отслеживаемым данным, находится в файлах surface_functions.txt и surface_modules.txt.

Содержимое файла surface_functions.txt:

Function eth_type_trans 0xffffffff82e03b10 6
Function inet_gro_complete 0xffffffff830339c0 3
Function __tcp_send_ack.part.0 0xffffffff82fa7be0 3
Function __tcp_transmit_skb 0xffffffff82f9fe10 11
Function do_raw_spin_lock 0xffffffff8123d380 13
Function __kasan_slab_free 0xffffffff815db0a0 1
Function tcp_rcv_established 0xffffffff82f8f8c0 15

Рассмотрим функцию eth_type_trans:

Функция eth_type_trans

В логе ssh_login_taint.log можно увидеть зарегистрированные вызовы этой функций. Ниже пример одного из стэков вызовов с функцией eth_type_trans:

Load:
Process name: swapper/0 cr3: 0x10a58e000
Tainted access at ffffffff82e03d55
Access address 0xffff88810bf6644c size 2 taint 0xffff
icount: 50506898698
Module name: /home/user/5.10.91/vmlinux base: 0xffffffff80e00000
Call stack:
0: ffffffff82e03d55 in func ffffffff82e03b10 /home/user/5.10.91/vmlinux::eth_type_trans
1: ffffffff827d11e6 in func ffffffff827d0cf0 /home/user/5.10.91/vmlinux::e1000_clean_rx_irq
2: ffffffff827d927c in func ffffffff827d8a80 /home/user/5.10.91/vmlinux::e1000_clean
3: ffffffff82d24bc5 in func ffffffff82d24860 /home/user/5.10.91/vmlinux::net_rx_action

Данная функция принимает пакеты из внешней сети и, следовательно, должна быть включена в поверхность атаки ядра. Поскольку функция eth_type_trans входит в модуль net/ethernet/eth.c, этот модуль тоже должен быть помещён в реестр модулей, составляющих поверхность атаки ядра.