Оценка безопасности различных дистрибутивов Linux

Лаборатория компании MWR Infosecurity провела сравнительный анализ дистрибутивов Linux с точки зрения информационной безопасности. Результаты исследования изложены в статьях "Анализ безопасности кода, выполняемого в адресном пространстве пользователя (userspace)" и "Анализ безопасности кода ядра".

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

Различные дистрибутивы по-разному находят компромисс между защищенностью и производительностью/поддержкой кода программного обеспечения. В статье сравнивается пять популярных дистрибутивов актуальных версий: Debian 5.0.4, Fedora 13, OpenSUSE 11.2, Ubuntu 10.04 и Gentoo (не перекомпилированная стабильная Hardened-ветка дистрибутива, Stage 3). По мнению авторов статьи, первые четыре из перечисленных дистрибутивов лидируют по количеству инсталляций, а Hardened-версия Gentoo выбрана как демонстрация дистрибутива, который включает в себя практически все известные методы защиты кода.

Сравнение проводилось в виртуальной среде KVM и с включенным NX-битом (защита от выполнения в сегменте данных) на процессоре Intel в 32-разрядном режиме. Сравнение выполнялось при помощи модифицированного Python-скрипта checksec.sh. В тестах выполнялась проверка процессов в графической (X11) пользовательской сессии, организованной через ssh (в сессии присутствовал sshd) и работающего web-браузара Mozilla Firefox. Стоит отметить, что количество процессов, инициированных графической сессии может существенно отличаться в различных дистрибутивах, например, от 34 в Gentoo до 96 - в сессии Ubuntu.

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

  • RELRO - защищает структуры исполняемого ELF-файла (изменение которых позволяет взломщику изменить ход выполнения программы) путем модификации секций PLT (Procedure Linking Table) или GOT (Global Offset Table) ELF-файла. При полном RELRO, вся таблица GOT перед началом исполнения в памяти помечается доступной только для чтения и таким образом предотвращает свою модификацию потенциальным злоумышленником. Частичный режим RELRO защищает только PLT. Кроме того, оба метода реорганизуют структуры данных ELF таким образом, что упомянутые таблицы помещаются перед остальными структурами данных ELF, что затрудняет для атакующего кода возможность расширения GOT и PLT.

    Так как RELRO требует, чтобы все связи исполняемого кода были разрешены до начала его работы, это может привести к заметному ухудшению производительности при старте программ, которые требуют для работы большого количества разделяемых библиотек (shared libraries).

    Тесты показали, что Debian и Fedora практически не используют RELRO, частичный режим RELRO реализован для всех процессов в SuSE и Ubuntu (для наиболее критичных, как dbus-daemon используется полный RELRO). В Gentoo - напротив для всех процессов реализован полный RELRO, за исключением Xorg-сервера, собранного с частичном RELRO.

  • Stack Smashing Protection (SSP) - защита от разрушения стека, называемая еще канареечной проверкой (канарейки в угольных шахтах в Англии до появления химических анализаторов воздуха использовались как индикаторы метана, до того как смесь становилась взрывоопасной - прим. пер). Эта защита базируется на помещении в стек маленьких меток - случайных чисел, генерируемых при старте программы, которые проверяются при работе со стеком, обычно при завершении работы функции. Вредоносный код переполнения буфера обычно помещается в стек и, таким образом, разрушает метки. Работа механизмов SSP обнаруживает разрушение и аварийно завершает взломанный процесс.

    Тесты показали, что SSP интенсивно используется Fedora, SuSE и Ubuntu - около 80% процессов используют эту защиту, а Debian и Gentoo - почти не используют (10%).

  • FORTIFY_SOURCE - свойство компилятора, который автоматически подменяет незащищенные от переполнения буфера библиотечные функции их защищенным эквивалентом, таким образом пытаясь защитить код от уязвимости, связанной с переполнением стека. Подробнобное описание FORTIFY_SOURCE можно получить здесь и здесь.

    Тесты показали интенсивное использование FORTIFY_SOURCE во всех сравниваемых дистрибутивах, кроме Debian данный метод применяется для порядка 80% процессов, а в Hardened Gentoo - для почти 90%.

  • PIC/PIE (Position Independent Code/Executable) - исполняемый позиционно-независимый код. Возможность предсказания где какие области памяти находятся в адресном пространстве процесса безусловно является подспорьем для взломщика. Несмотря на свойства операционных систем по случайному размещению пользовательского кода в памяти, большинство пользовательских программ продолжают загружаться и выполняться с предопределенного адреса виртуальной памяти процесса, так как не скомпилированы с опцией PIE. Напротив, использование PIE позволяет операционной системе загружать секции исполняемого кода в память произвольным образом, что существенно усложняет взлом. Понятно, что в 64-битных системах эта возможности обеспечивается лучше, чем в 32-битных - благодаря бóльшему по размеру виртуальному адресному пространству процесса.

    В исследуемых инсталляциях Gentoo показал использование PIE для 100% работающих процессов, в то время как в остальных рассматриваемых дистрибутивах процент был много меньше - от 8% в Debian до 21% в SUSE. Из остальных дистрибутивов стоит отметить, что только в Ubuntu, с данной опцией был собран браузер Firefox, который безусловно можно причислить к потенциально часто атакуемым.

Описанные выше методы применимы к процессам, работающим в пользовательском адресном пространстве Linux (userspace), и работа большинства из них невозможна без соответствующей поддержки ядра Linux. Представленное далее сравнение затрагивает только возможности ядра для обеспечения рассмотренных методов защиты пользовательского кода (а иногда относится к аспектам функционирования самого ядра) и не касается механизмов SELinux, Grsecurity RBAC и AppArmor.

Безопасность ядра имеет очень большое значение, так как возможность выполнения даже незначительно вредоностного кода в режиме ядра может сделать бесполезной всю систему безопасности userspace, описанную выше. Тестирование проводилось на тех же дистрибутивах - Debian (версия ядра 2.6.26-2-686), Fedora (2.6.33.6-147.fc13.i686), Gentoo (2.6.32-hardened-r9), OpenSuse (2.6.31.12-0.2-default) и Ubuntu (2.6.32-23-generic). Рассматривались параметры:

  • mmap_min_addr (/proc/sys/vm/mmap_min_addr) - минимальный адрес виртуальной памяти userspace, который может быть назначен пользовательской программе. Может иметь определенный смысл в контексте безопасности, когда код злоумышленника может спровоцировать разыменование NULL-указателя в коде ядра. Минимальным адресом указывается ненулевое значение так как по нулевому адресу может быть помещен предварительно подготовленный исполняемый код, который может быть теоретически выполнен.

    Все тестируемые дистрибутивы устанавливают значение данного параметра в 4096 или 65536. Во втором случае система делает невозможным выполнение программы в первых 64Kb виртуальной памяти. Заметим, что значение 4096 также усложняет доступ к нулевой странице, но не делает его невозможным. Также следует отметить, что не все пользовательские программы работают корректно при невозможности доступа к первым 64Kb виртуальной памяти (напирмер, wine требует установки mmap_min_addr в 0).

  • randomize_va_space (/proc/sys/kernel/randomize_va_space) - указывает на то, какие секции пользовательских программ при старте могут получать случайные адреса: значение 0 отключает эту возможность, "1" - дает возможность случайно распределять адреса для стека, VDSO (Virtual Dynamically-linked Shared Object, linux-gate.so - разделяемой библиотеки предоставляющей таблицу системных вызовов) и адресов для работы вызова mmap(). Значение randomize_va_space также предполагает случайное распределение выполняемых секций пользовательских процессов и разделяемых библиотек, скомпилированных в режиме PIC/PIE. Значение "2", дополнительно к предыдущему выделяет случайный виртуальный адрес для "кучи" (process heap).

    Для всех тестируемых дистрибутивов значение randomize_va_space установлено в "2", однако замечено, что в Debian начальный адрес "кучи" постоянен для всех процессов, т.е поведение системы согласуется с установкой randomize_va_space в "1".

  • paxtest - набор программных средств, разработанное Питером Буссером (Peter Busser) и Брэдом Шпенглером (Brad Spengler) для тестирования различных механизмов защиты памяти. Суть метода в попытке выполнить случайный код различными способами в различных областях памяти с использованием различных техник. Результаты проверки представлены в следующей таблице:
  Debian Fedora Gentoo OpenSuse Ubuntu
Executable anonymous mapping Vulnerable Killed Killed Vulnerable Killed
Executable bss Vulnerable Killed Killed Vulnerable Killed
Executable data Vulnerable Killed Killed Vulnerable Killed
Executable heap Vulnerable Killed Killed Vulnerable Killed
Executable stack Vulnerable Killed Killed Vulnerable Killed
Executable shared library bss Vulnerable Vulnerable Killed Vulnerable Vulnerable
Executable shared library data Vulnerable Vulnerable Killed Vulnerable Vulnerable
Executable anonymous mapping (mprotect) Vulnerable Vulnerable Killed Vulnerable Vulnerable
Executable bss (mprotect) Vulnerable Killed Killed Vulnerable Vulnerable
Executable data (mprotect) Vulnerable Killed Killed Vulnerable Vulnerable
Executable heap (mprotect) Vulnerable Killed Killed Vulnerable Vulnerable
Executable stack (mprotect) Vulnerable Vulnerable Killed Vulnerable Vulnerable
Executable shared library bss (mprotect) Vulnerable Vulnerable Killed Vulnerable Vulnerable
Executable shared library data (mprotect) Vulnerable Vulnerable Killed Vulnerable Vulnerable
Writable text segments Vulnerable Vulnerable Killed Vulnerable Vulnerable
Return to function (strcpy) Vulnerable Vulnerable Vulnerable Vulnerable Vulnerable
Return to function (memcpy) Vulnerable Vulnerable Vulnerable Vulnerable Vulnerable
Return to function (strcpy, PIE) Vulnerable Vulnerable Vulnerable Vulnerable Vulnerable
Return to function (memcpy, PIE) Vulnerable Vulnerable Vulnerable Vulnerable Vulnerable

Как видно из результатов тестов, ядра всех тестируемых дистрибутивов подвержены уязвимостям типа "return-to-function", позволяющим вредоносному коду использовать корректные системные функции в своих целях. Атаки такого типа достаточно сложно отличить от "легального" кода. Лучшая защищенность может быть достигнута с использованием 64-битного адресного пространства, так как согласно данной публикации 32-битное адресное пространство может быть просто просканировано вредоносным кодом для поиска искомого значения данных.

Следует отметить, что кроме Hardened Gentoo с патчем от Grsecurity, ядра других дистрибутивов в большей или меньшей степени подвержены атакам, в частности, Debian и OpenSuSE не предоставляют дополнительной защиты, в соответствии с paxtest. При этом в Fedora и Ubuntu не дают возможности записывать данные в определенные области памяти с последующем выполнением этих данных. Ядро Fedora даже выдержало тесты с сегментами памяти данных, в которые была попытка записи кода с последующим его выполнением. Однако у всех, кроме Hardened Gentoo, ядер сегмент с выполнимым кодом программы (text) оказался доступным для записи. Это делается намеренно, когда код программы или разделяемой библиотеки не является позиционно независимым и может потребоваться его легальное перемещение (загрузчиком, во время выполнения). Другой пример, когда требуется перемещение кода, это так называемые функции-трамплины - вложенные функции, генерируемые gcc. Подробнее о таких функциях написано в документации на gcc - здесь и здесь.

Еще один результат paxtest касается случайного распределения объектов в адресном пространстве процесса:

  Debian Fedora Gentoo OpenSuse Ubuntu
Anonymous mapping randomisation test 9 bits 12 bits 17 bits 12 bits 12 bits
Heap randomisation test (ET_EXEC) No randomisation 14 bits 23 bits No randomisation 13 bits
Heap randomisation test (PIE) 12 bits 18 bits 23 bits 12 bits 14 bits
Main executable randomisation (ET_EXEC) No randomisation No randomisation 15 bits No randomisation No randomisation
Main executable randomisation (PIE) 12 bits 12 bits 15 bits 12 bits 12 bits
Shared library randomisation test 10 bits 3 bits 17 bits 10 bits 12 bits
Stack randomisation test (SEGMEXEC) 10 bits 19 bits 23 bits 19 bits 19 bits
Stack randomisation test (PAGEEXEC) 10 bits 19 bits 23 bits 19 bits 19 bits

paxtest по разному выполняет проверку для обычного и PIC/PIE-кода. Правила случайного распределения памяти основаны на количестве битов, используемых для вычисления случайного адреса, например 16-битное значение дает 2^16=65566 вариантов, и в среднем на поиск искомого адреса злоумышленнику нужно будет сделать 32К переборов. Из тестов видно, что ядра всех, кроме Hardened Gentoo предлагают примерно одинаковую степень энтропии в вычислении случайного адреса. Исключение тут делается в ядре Fedora с 3bit entropy для разделяемых библиотек с позиционно-независимым кодом.

Главный вывод из написанного состоит в том, что ни один из рассмотренных дистрибутивов, кроме, пожалуй, Hardened Gentoo, не уделяет должного внимания безопасности.

Полный текст статьи читайте на OpenNet