tmp.0ut Volume 5. Полный обзор нового выпуска про ELF, Linux и руткиты

2011
tmp.0ut Volume 5. Полный обзор нового выпуска про ELF, Linux и руткиты

Свежий tmp.0ut Volume 5 выглядит примерно так, будто группе людей дали ELF, ассемблер, ядро Linux и команду «посмотрим, насколько далеко можно зайти». В оглавлении 21 позиция, включая вступление и музыкальный микс. Между ними 19 содержательных материалов про экстремально маленькие ELF, метаморфный код, необычное управление потоком, полиглоты, загрузчики, защиту программ, руткиты, Java-байткод и перестановку функций в памяти.

Я бы не называл номер просто журналом про вредоносный код. Самые интересные статьи исследуют границу между спецификацией и реальным поведением системы. Что ядро Linux действительно проверяет при execve, сколько структуры ELF можно выбросить, можно ли обнаружить вмешательство в системные вызовы без доверия самому ядру, насколько далеко реально переместить функции при загрузке программы. Именно за такие эксперименты tmp.0ut и стоит читать.

Дисклеймер. В выпуске есть материалы о вирусах, руткитах, шелл-коде и модификации ядра. Разбирать такие техники имеет смысл для исследований, обучения и защиты собственных систем. Не применяйте описанные подходы для несанкционированного доступа, скрытого наблюдения, взлома чужой инфраструктуры или нарушения правил сервисов. Учитывайте законодательство своей страны, включая требования российского законодательства.

Пять материалов, с которых я бы начал

Первое место я бы отдал Inside and Outside a 57-Byte x86-64 Linux ELF. Автор методично разбирает загрузчик ELF в Linux и выясняет, насколько мало данных нужно ядру, чтобы признать файл исполняемым. Получается 57-байтовый ELF64, который проходит execve и становится процессом. Правда, такой минимальный вариант сразу падает, потому что в нём почти нечего исполнять.

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

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

Второй материал, который я бы точно не пропускал, Detecting syscall hooks with side-channels. PinkNoize предлагает обнаруживать перехват системных вызовов по изменениям в кэше инструкций процессора. Идея особенно интересна из-за модели угроз. Если руткит уже работает в ядре, спрашивать ядро, всё ли с ним хорошо, довольно бессмысленно. Автор пытается получить сигнал снизу, от аппаратного поведения процессора.

Эксперимент использует особенности L1-кэша инструкций и строит отпечатки выполнения системных вызовов. После вмешательства дополнительный код меняет след в кэше, что позволяет заметить перехват без прав суперпользователя. Автор выпустил инструмент l1thography и показал эксперимент на Raspberry Pi 5.

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

Третьим я поставил бы Overview of code virtualization. Это длинный учебник по виртуализации кода. Автор начинает с мутаций инструкций, сокрытия констант и запутывания графа управления, после чего переходит к собственной виртуальной машине. Исходные x86-64 инструкции превращаются в пользовательский байткод, а внутри программы появляется интерпретатор с виртуальными регистрами, стеком, указателем инструкции, диспетчером и обработчиками команд.

Ценность статьи не столько в новизне, сколько в последовательности. После архитектуры автор показывает обратный процесс, как аналитик находит инициализацию виртуальной машины, определяет диспетчер, разбирает обработчики, восстанавливает значения команд и пишет дизассемблер пользовательского байткода. Для первого серьёзного знакомства с защитами класса VMProtect или Themida материал получился удачным.

Но один тезис в статье уже не выдерживает проверки. Автор пишет, что Denuvo фактически не получала полноценного взлома после старой волны атак. К моменту выхода номера ситуация изменилась. Появились новые гипервизорные обходы, а затем и свежие взломы защищённых игр. О резком изменении положения Denuvo писали, например, Tom's Hardware и другие профильные издания. Архитектурная часть статьи от этого слабее не становится, а историческая оценка DRM уже устарела.

Четвёртое место занимает не одна статья, а трилогия TMZ. В halfexec автор практически заново собирает часть поведения execve в пользовательском пространстве. Загрузчик написан на x86-64-ассемблере и умеет работать с ET_EXEC, ET_DYN, PIE, статическими и динамическими программами, PT_INTERP и TLS. Идея проста только на словах. До передачи управления в _start системе приходится подготовить отображения памяти, стек, аргументы, переменные окружения, вспомогательный вектор и другие детали, которые обычный программист почти никогда не видит.

В halfshelf область задачи намеренно сужается до статического PIE с одним PT_LOAD. Затем автор спрашивает, сколько сведений нужно сохранить, если удалить заголовок ELF и таблицу программных заголовков. Финальный phork упаковывает такой обезглавленный образ вместе с метаданными и небольшим загрузчиком обратно в один обычный ELF. При запуске загрузчик читает собственный файл, восстанавливает образ в памяти и передаёт управление полезной нагрузке без временного файла.

Пятое место я бы разделил между двумя работами про изменение исполняемого кода. В Fine grained load time ASLR elfmaster развивает проект Shiva и перемещает отдельные функции ELF по новым адресам во время загрузки. Получается более мелкая рандомизация, чем обычный ASLR, который в основном двигает крупные области целиком. Пока это исследовательский прототип. Нужны сохранённые текстовые релокации, программа должна учитывать большую модель адресации, поддерживаются не все типы релокаций, а сам автор перечисляет дальнейшую работу.

Рядом стоит Static Kernel Patching Redux. bah возвращается к старой идее патчинга образа ядра Linux на диске и переносит её на современные x86-64, UEFI и BIOS. Автор сообщает о тестах на широком диапазоне ядер и использует kSHELF как загружаемую полезную нагрузку. Но граница исследования тоже видна хорошо. Secure Boot, Unified Kernel Images и другие современные варианты загрузки остаются направлениями дальнейшей работы, поэтому универсальным способом модификации любого современного Linux подход считать нельзя.

Весь выпуск по порядку

Материал О чём речь Моя оценка
Interview with Doug McIlroy Большое интервью с Дугласом Макилроем о Bell Labs, Multics, раннем Unix, C, конвейерах, отладке и программировании при жёстких ограничениях памяти. Обязательно читать. История Unix из первых рук. Особенно хорош рассказ о появлении конвейеров и философии маленьких программ.
57-Byte ELF Минимальный ELF64, реальные требования загрузчика Linux и перенос исполняемого кода в имя файла. Один из лучших текстов номера. Здесь отлично видно расхождение спецификации и реализации.
440-BYTE METAMORPHIC ELF-64 VIRUS Миниатюрная программа, которая меняет собственное бинарное представление перестановкой независимых инструкций, сохраняя поведение. Красивый бинарный гольф, но не модель современного вредоноса. У автора также есть спорный подсчёт количества возможных форм. Независимые перестановки блоков в общем случае комбинируются произведением, а не простым сложением вариантов.
PERL Stuff Набор экспериментов с мутацией и перестройкой Perl-кода. Самый слабый редакционно материал. Кода много, объяснений почти нет. Скорее заметка для своих, чем законченная статья.
XLAT is All You Need 79-байтовый позиционно-независимый декодер, где редкая инструкция XLATB заменяет привычное арифметическое преобразование таблицей подстановки. Хороший пример идеи «логика хранится в данных». Практическая ценность ограничена, исследовательская ценность заметно выше.
Control Flow That Isn't There Состояние хранится во флагах процессора, выбор пути зависит от времени, а один набор байтов допускает вход с разных смещений. Очень tmp.0ut. Полезно для понимания того, почему статический дизассемблер иногда строит убедительный, но неверный граф управления.
Brainfuck as a ROP Compiler Brainfuck компилируется непосредственно в цепочку ROP-гаджетов. Стековый указатель фактически становится счётчиком команд. Одна из самых забавных идей выпуска. Хорошо показывает ROP не как отдельный трюк эксплуатации, а как полноценную вычислительную модель.
How the Linux kernel loads executable files Разбор реального пути загрузки исполняемых файлов ядром Linux с акцентом на x86, ELF и различия между вариантами ABI. Базовый технический материал номера. Его лучше читать перед статьёй про полиглоты.
Polyglot ELF Один файл одновременно строится так, чтобы представлять ELF32 и ELF64, причём разные анализаторы могут интерпретировать структуру по-разному. Интересен прежде всего криминалистам и разработчикам анализаторов файлов. Простая проверка поля EI_CLASS не всегда отражает всю реальность.
Detecting syscall hooks with side-channels Поиск перехватов системных вызовов по аппаратному следу в L1-кэше инструкций. Самая интересная защитная работа выпуска. Ограничений много, но направление сильное.
Overview of code virtualization Большой учебник по обфускации через собственные виртуальные машины и обратному анализу такого кода. Полезно начинающему реверсеру. Исторический тезис про стойкость Denuvo нужно читать с поправкой на свежие события.
halfexec Пользовательский ELF-загрузчик на ассемблере, воспроизводящий значительную часть подготовки процесса. Отличный способ понять, что на самом деле скрывается за запуском программы.
halfshelf Загрузка узкого класса статических PIE и эксперимент с удалением заголовков ELF. Менее универсально, зато глубже. Хороший второй акт трилогии.
phork Самозагружаемый упаковщик, который хранит урезанный образ внутри обычного исполняемого файла. На мой вкус, самая красивая часть трилогии TMZ.
Self-Extraction Using Reachability Analysis Эксперимент с новым стандартным Class-File API Java. Автор анализирует достижимые методы, переносит нужный байткод и модифицирует существующий class-файл. Неожиданно современная тема для такого журнала. Хорошо показывает, что удобный официальный API для трансформации байткода полезен не только обычным инструментам разработки.
RDOFF Virus Netspooky оживляет давно заброшенный формат RDOFF из истории NASM и строит для него экспериментальный файловый вирус. Практической угрозы почти нет именно потому, что RDOFF фактически никому не нужен. Зато археология форматов великолепная.
BGGP6 Recap Итоги Binary Golf Grand Prix. В соревнование поступило 36 работ, среди них 15 полиглотов, 11 самовоспроизводящихся файлов и десятки других миниатюрных конструкций. Хороший источник идей для тех, кому нравится бинарный гольф и намеренное злоупотребление форматами файлов.
Fine grained load time ASLR Перемещение отдельных функций ELF во время загрузки через Shiva вместо рандомизации только крупных областей процесса. Серьёзное исследование, но пока прототип. До прозрачной защиты произвольных Linux-программ ещё далеко.
Static Kernel Patching Redux Модификация современных x86-образов ядра Linux на диске, работа с UEFI, BIOS, PE и ELF. Самый тяжёлый материал номера. Читать после остальных, иначе загрузочная кухня Linux быстро превращается в набор непонятных смещений.
tmp.0ut 5 mixtape Музыкальный микс от blotter. Да, у технического журнала про ELF снова есть собственный саундтрек. Формально бесполезно, культурно абсолютно уместно.

Где выпуск особенно хорош, а где нужно держать голову включённой

Главная сильная сторона номера заключается в постоянном переходе от документации к эксперименту. Авторы не ограничиваются фразой «ELF устроен так». Они спрашивают, какие поля ядро действительно читает, какие значения можно подделать, какие структуры можно удалить и что случится после этого. Такой подход полезен далеко за пределами вирусологии. Разработчики песочниц, EDR, анализаторов бинарных файлов, упаковщиков и средств цифровой криминалистики сталкиваются с теми же расхождениями между форматом «по стандарту» и форматом «который реально принимает система».

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

Слабая сторона у tmp.0ut традиционная. Некоторые тексты демонстрируют эффект гораздо убедительнее, чем его практическую значимость. 57-байтовый ELF великолепен как исследование загрузчика, но не как полезный исполняемый формат. RDOFF-вирус работает с практически мёртвым форматом. 440-байтовый метаморфный пример намеренно примитивен и легко обнаруживается. gASLR пока требует специально подготовленного бинарника. Кэшевый детектор руткитов зависит от конкретного процессора и эталонного профиля.

И это скорее плюс, если читать журнал правильно. tmp.0ut не продаёт готовый «продукт для защиты Linux». Журнал показывает необычные свойства вычислительных систем и доводит идеи до работающего доказательства концепции. Переносить выводы на реальную инфраструктуру нужно уже самостоятельно.

Отдельно замечу, что анонсированный конкурс Linux-руткитов пока не завершился публикацией результатов. Во вступлении редакция пишет, что результаты объявят позднее. Поэтому воспринимать пятый номер как окончательно закрытый выпуск пока рано.

Что читать в первую очередь

Если времени мало, я бы прошёл выпуск по цепочке 57-byte ELF, затем загрузчик ядра Linux, полиглот ELF, обнаружение перехватов по кэшу и трилогию halfexec. После такой базы уже имеет смысл идти в виртуализацию кода, gASLR и патчинг ядра.

В целом пятый tmp.0ut получился сильнее как журнал об устройстве исполняемых программ, чем как журнал о вирусах. Вирусы и руткиты здесь скорее инструменты для исследования границ системы. Главный урок выпуска я сформулировал бы проще. Формат файла, дизассемблер, загрузчик, ядро и процессор могут смотреть на одни и те же байты совершенно по-разному. Чем ниже спускаешься по стеку, тем меньше работают привычные предположения. Ради такого эффекта номер и стоит прочитать целиком.

Alt text
Обращаем внимание, что все материалы в этом блоге представляют личное мнение их авторов. Редакция SecurityLab.ru не несет ответственности за точность, полноту и достоверность опубликованных данных. Вся информация предоставлена «как есть» и может не соответствовать официальной позиции компании.
01001
SOC
Security Vision SIEM
ЭКСПЕРТИЗА И АНАЛИТИЧЕСКИЕ ИНСТРУМЕНТЫ SOC — В ЕДИНОМ КОНТУРЕ.
ОТ КОНТРОЛЯ ДАННЫХ И ВЫЯВЛЕНИЯ АТАК ДО РАССЛЕДОВАНИЯ И РЕАГИРОВАНИЯ.
УЗНАТЬ БОЛЬШЕ
18+. Реклама. Рекламодатель ООО «Интеллектуальная безопасность», ИНН 7719435412

Юрий Кочетов

Здесь я делюсь своими не самыми полезными, но крайне забавными мыслями о том, как устроен этот мир. Если вы устали от скучных советов и правильных решений, то вам точно сюда.