
Исходный код и файлы конфигурации, относящиеся к нашей статье в MISC96
Этот репозиторий является дополнением к статье, опубликованной в журнале MISC №96.
Нам удалось надёжно повысить свои привилегии на нашей виртуальной машине с включёнными SMEP / SMAP и KASLR. Однако следует отметить, что система остаётся в нестабильном состоянии и возникновение oops весьма вероятно.
В папке configs/ вы найдёте файлы конфигурации для ядра Linux
и Busybox, каждый из которых немного отличается от стандартных.
Папка binaries/ содержит все предварительно собранные бинарные файлы,
необходимые для воспроизведения нашей тестовой среды, включая готовую rootfs,
которую можно использовать с QEMU.
linux-stable — это git-подмодуль, указывающий на уязвимую ревизию ядра
Linux. Используйте git submodule update --recursive, чтобы получить его
(если у вас есть хотя бы 1 ГБ свободного места на системе...). То же самое
касается и busybox.
Наша среда основана на виртуальной машине QEMU x86 с папкой, общей
с хостом через 9P. Уязвимая версия ядра (ff33952e4d23) компилируется
вместе со статически слинкованной сборкой Busybox.
Наша конфигурация довольно проста, поскольку нам не нужно поддерживать
какие-либо экзотические архитектуры или оборудование. Она была сгенерирована
выполнением make defconfig, и некоторые функции были включены для поддержки
сетевых возможностей QEMU и общего доступа к папкам:
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_MEMORY_BALLOON=y
CONFIG_BALLOON_COMPACTION=y
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_NET_9P_DEBUG=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_BLK_SCSI=y
CONFIG_VIRTIO_NET=y
CONFIG_HVC_DRIVER=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_HW_RANDOM_VIRTIO=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_PCI_LEGACY=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
CONFIG_9P_FS=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_9P_FS_SECURITY=y
GDB-скрипты и отладочные символы также были добавлены для упрощения разработки первых PoC:
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_GDB_SCRIPTS=y
Обратите внимание, что в этой версии KASLR включён по умолчанию на x86.
Поскольку ядро отображается по разным адресам после каждой перезагрузки,
GDB не сможет сопоставить с ним файл символов. У вас есть два варианта:
проводить тесты без KASLR или передать базовый адрес ядра команде
symbol-file при загрузке символов в GDB.
После компиляции вы найдёте bzImage в linux-stable/arch/x86/boot/bzImage.
Этот файл присутствует в binaries/bzImage, а наш файл конфигурации —
в confifs/kernel.config. Чтобы использовать его, вам нужно лишь скопировать
его как .config в linux-stable.
Мы использовали последнюю стабильную версию Busybox, 1.28. Единственный
параметр, который нужно изменить, — это CONFIG_STATIC, установите его
в y. Компиляция не должна вызвать никаких проблем.
Наш файл конфигурации доступен в configs/busybox.config, а статически
скомпилированный бинарный файл — в binaries/busybox. Как и для Linux,
просто скопируйте его как .config в папку с исходниками Busybox.
Busybox уже реализует init-процесс, который попытается выполнить
/etc/init.d/rcS. Обычно он предоставляется вашим дистрибутивом (возможно,
под другим именем), но здесь нам придётся сделать это самостоятельно!
Этот скрипт создаст и смонтирует несколько обязательных системных папок
(proc, sys, dev), нашу папку, общую с хостом, и опустит нас
в непривилегированную оболочку:
for i in $(seq 1 9); do mknod /dev/tty$i c 4 1; done
mknod -m 0666 /dev/null c 1 3
mknod -m 0660 /dev/ttyS0 c 4 64
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs none /dev
mkdir -p /mnt/share
mount -t 9p -o trans=virtio share /mnt/share/ -oversion=9p2000.L,posixacl,sync
chmod 777 /mnt/share/
export ENV=/etc/profile
setsid cttyhack setuidgid 1000 sh
umount /proc
umount /sys
umount /dev
poweroff -f
Файл /etc/profile не обязателен, но довольно полезен во время наших
тестов, особенно когда эксплойт был ненадёжным и требовалось несколько
попыток для получения root-привилегий.
Процесс написания эксплойта довольно подробно описан в MISC 96: мы используем
unsafe_put_user для поиска в памяти базового адреса кучи.
Затем тысячи вызовов clone позволяют нам распылить множество структур
cred в памяти. Во время наших тестов их положение в памяти было гораздо
более «постоянным», чем при использовании fork, поскольку для новой задачи
выделяется меньше структур.
Выход из дочернего процесса вызывает kernel oops из-за ошибочного запроса страницы; это необходимо корректно обработать.
Если вы хотите повысить надёжность этого эксплойта или добавить документацию, ваш вклад приветствуется! Мы также могли допустить ошибки или неточности в некоторых концепциях — не стесняйтесь открыть issue, если считаете, что что-то не так.
Ядро Linux
Эксплуатация