Готовим NSA SELinux
tutorial
Привет
Хабр! Данным постом я хочу немножно отвлечь многоуважаемое сообщество
от пересуд на тему АНБ, и вместо этого заполнить пробел в описании одной
их технологии, написав нечто среднее между «отключайте SELinux» и
«посвятите ему лучшие годы чтобы понять малую часть». На самом деле, обе
эти точки зрения одинаково далеки от правды — технология достаточно
проста, прозрачна и позволяет сделать очень многое. Однако, хочу
предупредить об огромном количестве букв, и достаточно узкой целевой
аудитории, т.к. нижеописанное будет интересно далеко не всем. Если вы
давно хотели понять, что такое SELinux, но не знали с какой стороны
подступиться — эта статья для вас. Если вы давно все это знаете и
успешно применяете, то я допустил достаточно неточностей, чтобы мы
смогли обсудить это в комментариях. Ну а эксперты по ИБ с мировым именем
могут смело проматывать в самый конец и начинать играть, у меня есть
планы на продолжение :-)
Я не буду в статье касаться тем связанных с АНБ в целом, способностью
расшифровывать RSA, прослушкой и прочими медийными аспектами — no hype,
no FUD, only technology. Мы будем с разной степенью активности влезать в
разные исходники, добавлять свои условия в само сердце MLS, возможно
внедряя свои уязвимости (мы тоже делаем ошибки), и после этого попытаемся взлететь
проведем тесты. Иными словами, я описываю что и как, а вы после этого
уже не смотрите на SELinux как на неведому зверушку и обитель зла от
вероятного противника, а смело начинаете использовать эту технологию во
благо. Особенно учитывая, что она уже включена во всех ваших андроидах
(>4.3) и многих дистрибутивах.
Итак, если вам все еще интересно, и вы не боитесь просидеть неделю в одном из многочисленных спойлеров, тоПредварительные чтенияЯ
подразумеваю, что у вас уже есть опыт работы с Linux в достаточном
объёме, чтобы развернуть свой любимый дистрибутив в виртуальном
окружении. Я буду делать все на примере Debian, но если вы решите
повторить сей путь, то все это можно (и очень даже нужно) проделать на
наиболее вам удобном и привычном дистрибутиве — в процессе вы узнаете
про него много нового. Я постарался написать эту статью как обучающий
материал, чтобы любой желающий мог пошагово повторить. Так же я
подразумеваю, что вас не затруднит читать техническую документацию на
английском — информации по SELinux на русском пока что крайне мало.
Общая информация по технологииВокруг SELinux вертится столько слухов, что вы будете удивлены, насколько небольшая по объему у нас вводная, всего три ссылки:- RH Guide: если какая-то команда непонятна, с большой вероятностью вы найдете описание в нем. Откройте его в отдельном табе, пригодится.
- Конспект
лекции Eli Billauer: рассматривайте как основной сборник фактов. По
нему можно быстро понять что к чему, и знать, что именно спрашивать у
гугла.
- Написание политик.
Несмотря на десятилетнюю давность документа, в нем описано достаточно
ключевых моментов для понимания внутреннего устройства SELinux, и как
его ковырять.
Это основное, что я рекомендую к прочтению до того, как приступать к настройке, иначе вы постоянно будете возвращаться в этим документам. Есть множество других ресурсов, но вы до них обязательно дойдете, если захотите сделать что-то, отличное от включения/выключения булевых переменных.
Итак, когда вы все это прочитали, можем проверить себя простыми вопросами:- Что такое unconfined_t/unconfined_u, и почему SELinux нельзя на нем тестировать?
- Что является частным случаем, MLS или MCS?
- Чем отличается *.te от *.if от *.fc?
Ответы
Постановка задачи и предварительная настройкаТеперь, когда мы уже знаем что мы хотим, но не знаем как мы это будем реализовывать, можем сформулировать цели эксперимента: - Хотим настроить SELinux MLS (раз уж взялись, давайте по максимуму, а не готовое из репозитория
next->next->agree); - За основу хотим взять RefPolicy;
- Ну и после этого хотим проверить worst case scenario — нас поломали,
и не просто поломали, а получили UID=0, да не просто получили, а с
постоянным shell доступом, а root мы на user_u перемапить то и забыли. Я
намеренно специально делаю ряд подобных допущений, рассматривать будем
наихудший сценарий;
- Мы будем настраивать минимально необходимый экземпляр, иначе будет не статья, а сага о пятиста страницах;
СерверС вашего позволения, уберу под спойлер. YMMV, у вас
может быть и не Debian, да и установка в KVM ничем особенным не
отличается. Подойдет любой дистрибутив, установленный в минимальной
конфигурации в виртуальном окружении. Виртуальном — потому что удобнее,
минимальном — потому что быстрее.Детали Считаем, что основа для экспериментов готова.
Автоматизируем сборку политикПолитики мне было удобнее собирать
на локальной машине и в виде deb-пакета уже устанавливать на сервер.
Поэтому я пошел по пути наименьшего сопротивления.up'n'enter style
SELinux, первое знакомство.Сервер готов, система сборки готова, reference policy загружена, вот теперь
можно приступать к самому интересному. (Примерно на этом этапе, оценив
уже существующий объем статьи, закралась крамольная мысль разделить ее
на 25 :-).
Для первой сборки, определимся с параметрами, я выбрал такие:$ sed '/^#/d;/^$/d' build.conf
TYPE = mls
NAME = custom
DISTRO = debian
UNK_PERMS = reject
DIRECT_INITRC = n
MONOLITHIC = n
UBAC = y
CUSTOM_BUILDOPT =
MLS_SENS = 4
MLS_CATS = 32
MCS_CATS = 32
QUIET = n
Отличия от апстрима минимальны: включен MLS (значит при
сборке будут включаться все параметры из policy/mls и
config/appconfig-mls); включены дистро-специфичные макросы для debian,
что на самом деле не обязательно; политика не будет загружаться, если в
ядре будут определены разрешения, не отраженные в политике — вдруг у нас
ядро намного новее; ну и я существенно снизил количество уровней и
категорий — у нас будет всего 4 уровня секретности, в каждом по 32
категории. Пока что нам этого хватит. суть нумеро уно
Создаем все необходимые конфиги, которые мы будем править под свои нужды: make conf. Вначале правим правим появившийся policy/modules.conf
— я отключил (modulename=off) почти все модули в группе contrib. Плюс —
быстрее сборка, меньше модулей. Минус — возможное недоопределение
контекстов. Поясню на примере:- Контекст /dev/xconsole, хоть и относится больше к логгированию, определяется в модуле xserver;
- Отключив его, контекст стал наследоваться с директории /dev/;
- И с большой вероятностью все, что хотело писать в /dev/xconsole, и
было учтено в RefPolicy, тут же сломалось. Поправить — на ваш выбор:
либо включаем модуль xserver, либо переопределяем контекст в любом своем
локальном модуле.
contrib_off Как только мы начали править modules.conf, мы прошли точку невозврата, после которой мы должны понимать,
что мы делаем и почему. Возможное недоопределение контекстов — как раз
первый пример того, как наши действия влияют на систему.
Забегая вперед сразу скажу немного о замечательной утилите audit2allow:
она кушает audit.log, и в достаточно понятной форме (особенно с ключами
-Rev) выдает нам, что нам надо добавить в политике, чтобы данные
сообщения в логе больше не появлялись.Так вот, если вы где-либо (а это
практически везде) в интернете встретите рекомендациюgrep something-something /var/log/audit/audit.log | audit2allow -M mymegamodule
semodule -i mymegamodule
то следуйте ей только если вы отдаете себе отчет, что
именно вы сейчас сотворите — этот набор команд означает, что SELinux
будет разрешать все, до чего (потенциально жадное)
something-something попросило доступ, и даже немножко больше. Более
того, в случае MLS данный метод вообще не сработает — потому что в MLS
недостаточно создать разрешающее правило, нужно чтобы доступ
удовлетворял всем наложенным ограничениям по допускам и категориям.
Подобные действия равнозначны чистосердечному признанию: «да, я сегодня
совсем не хочу думать головой, мне проще разрешить все». Не делайте из
своей системы театр,
и не настраиватёте SELinux подобным образом — это все равно что
отлавливать все пакеты на фаерволе и скриптом превращать их в
разрешающие правила.
Теперь самое время запустить make install, и если все хорошо, то собрать наш пакет и поставить на сервер:dpkg -i /tmp/selinux-policy-custom*deb
sed -i 's/^SELINUX=.*$/SELINUX=enforcing/;s/^SELINUXTYPE=.*$/SELINUXTYPE=custom/' /etc/selinux/config
selinux-activate
reboot
Система перезагрузится, применит контексты согласно определенным в установленной политике (/etc/selinux/custom/contexts/files/*), перезагрузится еще раз и любезно предложит зайти.
When is rocking «rocking» and when is it «shaking» *Шеф, все
пропало. Ничего не работает. Мы даже не можем зайти по ssh — connection
closed by host. Знакомьтесь, SELinux. Как замечательно точно
сформулировал Eli Billauer:What is SELinux?
In a nutshell: a machine that tells you permission is denied. Тем
не менее, хорошо, если вы дошли до этого момента. Это именно то
поведение, которое нам нужно, и сейчас мы начнем разбираться, почему нас не пускает.суть нумеро дуо, на этот раз без плохих аналогий Ах
да, забыл сказать, что начиная с этого момента, вам понадобится доступ к
серверу не только по ssh, он может не работать. Благо, в нашем случае
это виртуальный сервер, всегда есть VNC/SPICE/etc
(ссылка спецом для ФСКН). Пробуем зайти локально — не пускает. Отличная
ситуация, чтобы сразу проиллюстрировать, как из нее выходить На этом этапе, audit.log содержит в себе все причины наших неудач,
почему мы не смогли зайти. Т.к. сейчас мы загрузились с отключенным
SELinux, первое, что имеет смысл сделать, это скопировать audit.log с
прошлой загрузки для последующего анализа, ведь при включенном SELinux у
нас это сделать просто так не получится.cp /var/log/audit/audit.log /root
wc -l /root/audit.log
195
Масштаб бедствия небольшой, двести строк. Настало время медленно спуститься с горы:Как читать логи Как исправлять Что исправлять
Итак, мы все настроили, система загружается в режиме enforcing. К этому
моменту, как правило, внимательный читатель уже обладает обширными
знаниями доработке модулей, бегло ориентируется в структуре политики,
искренне любит (или не менее искренне ненавидит) синтаксис m4, подписан
на рассылку NSA, знает два десятка источников информации по SELinux и
дюжину разработчиков поименно.
Настало время залезть еще немного глубже, на территорию, не сильно описанную в документациях.
MLSЕсли вы немного знакомы с всякими критериями оценки защищенности, то наверняка знаете, что их, во первых, превеликое множество (c отдельными(PDF) профилями(PDF), большая часть из которых разработана разного рода околовоенными организациями), и что на выходе получается некое количество попугаев, характеризующее жесткость предъявленных требований при прохождении. MLS
добавляет к уже существующим ограничениям SELinux еще два уровня
контроля, вертикальный (levels) и горизонтальный (categories). Первый —
это ни что иное как «допуски», где вышестоящий допуск подразумевает
доступ к нижестоящему («совершенно секретно» может читать документы с
грифом «секретно»), а второй — различные категории одного и того-же
уровня, где разрешение читать одну категорию вовсе не означает
разрешения читать остальные.
Поскольку оба этих уровня контроля могут быть назначены любым объектам, с
которыми работает SELinux, то это позволяет реализовывать практически
любые требования по классификации информации и ее потоков:- Иерархический доступ, TopSecret -> Secret -> Unclassified, для любых объектов. Полный список есть в директории flask;
- Маркировка как файлов, так и, например, сетевых соединений или таблиц в БД;
- Предотвращение утечки информации на низлежащие уровни независимо от прав пользователя в системе;
- Ограничение доступов по умолчанию для любых пользователей (в том
числе и root), с дальнейшим разграничением ролей в зависимости от
аутентификации.
- И прочий оверкилл для 99% систем.
Разумеется, все это требует тщательной проработки, прежде всего,
архитектуры системы, иначе у нас потом контрактные работники будут
раскладывать документы с грифом «Top Secret» по инстаграммам :-)
В рамках данного эксперимента я использовал вот такие уровни и категории:root@sandbox:~
Domain=Playbox
s0=SystemLow
s3:c0.c31=SystemHigh
s0-s3:c0.c31=SystemLow-SystemHigh
s1=Confidential
s2=Secret
s1.c0=Ninjas
s1.c1=Pirates
s1.c2=Jesuses
s2.c0=Aliens
s2.c1=BigBrother
Теперь настроим наш веб-сервер, как будто бы он
предназначен исключительно для внутреннего доступа, т.е. работает строго
на уровне s1 (Confidential). Это не необходимо для демонстрации, но
полезно для общего развития. Разумеется, IPSec и маркировку пакетов
настраивать не будем, иначе никто его не увидит, ограничимся локальным
контекстом. Поскольку у нас сейчас на тестовой машине настроен только
ssh, давайте выберем сервер, который не описан в RefPolicy:nginx Заводим пользователей и роли, например так:root/sysadm_r@sandbox:~
...skipped...
root/sysadm_r@sandbox:~
...skipped...
root/secadm_r@sandbox:~
root/secadm_r@sandbox:~
root/secadm_r@sandbox:~
root/secadm_r@sandbox:~
root/secadm_r@sandbox:~
Итого, получаем:- оба пользователя не могут писать данные в директории ниже своего минимального уровня;
- оба пользователя не могут читать из объектов выше своего уровня допуска;
- оба пользователя ограничены своей категорией. При добавлении
разрешющих правил на чтение других доменов они смогут читать только
файлы с категорией c0;
- root не может читать файлы пользователей, не изменив контекст;
- если у боба будет тот-же SELinux ID, что и у alice, он сможет читать ее файлы (если DAC разрешает) и видеть ее процессы;
- веб сервер не сможет писать никуда, кроме своих директорий, даже
если его попросят выложить core — у нас практически вся система в s0, а
он — s1.
Funky timeНу и теперь, наконец-то, будут слайды. Для
полноценной демонстрации, я купил под эту статью небольшую впску,
рядышком с АНБ, и все проделанное быстренько развернул на ней.
Непосредственно на этой системе можно посмотреть, что такое SELinux,
зайти под рутом и первым делом набрать rm -rf /* всенепременнейше,
позапускать всяких скриптов/сплойтов и руткитов, в общем, показать этим
АНБ кузькину мать. Но прежде, чем вы займетесь этим увлекательным делом,
давайте еще раз пробежимся как по допущениям, так и по ограничениям: В рамках этого обучающего курса, мы:- Считаем, что root доступ к серверу получил кто-угодно.
- Считаем, что ему можно входить по ssh и запускать интерактивный shell.
- Считаем, что root у нас незамаплен на user_u, как это сделал Russell Coker в своей play machine. Разумеется, этого допущения не рекомендуется делать в production (как и все предыдущие, конечно-же :-)
- Считаем, что мы не кастомизировали ядро (нет grsec, это я решил не включать в статью и тесты)
- Считаем, что у нас почти нет фаервола.
Если и есть в ИБ термин для состояния безопасности, в описании
которого есть слова «раздвигать» и «булки», то это именно оно. Все, что
отделяет от полной компрометации, это SELinux. Компрометация неизбежна,
но очень интересно, за какое время.Но так-же, есть то, для чего SELinux не преднасначен, а именно:- SELinux это не средство ограничения ресурсов. Он не спасет от :(){ :|:& };:.
Поэтому мне пришлось настроить небольшую защиту от fork bombs, но
все-же — не пробуйте; в лучшем случае, вас кикнет и вы больше не сможете
зайти, в худшем — если будете проявлять упрство — то и другие не смогут
зайти, пока я все не почищу.
- SELinux это не средство защиты от атак на другие ресурсы. Поэтому
мне пришлось ограничить доступ наружу с демо сервера. Если вы сможете
продемонстрировать, как вы отключаете SELinux или iptables — вы большой
молодец, но к следующей версии я это поправлю. Скорее всего, это косяк
не SELinux, а мой :-)
- Мы рассматриваем сервер в минимальной конфигурации, там нет
компиляторов/дебагеров и всего того, чего обычно на проде итак не
бывает. Версия полноценной MLS Play Machine будет позже, когда я
разверну это не на VPS, а на более контроллируемой инфраструктуре. Зато
есть scp — можно интересное копировать.
- И да, в лучших традициях организации, разработавшей SELinux, на
сервере заодно тестируется запись консольных сеансов :-) А то сами
понимаете, NSA, Аризона, Area51 недалеко, а тут рутовый доступ. Надо
писать, вдруг мне туда центральных процессоров понапихают вагон. Снимете
запись — вы тоже большой молодец, и тоже напишите в комментарии.
- 0day — на ваше усмотрение. Если всплывет, я конечно буду польщен. Хотя, кому я рассказываю :-)
Домен я не заводил, это для игрушки версии 0.0.2. Версия 0.0.1тут И да, отдельная просьба — please behave. Не надо убивать все рутовые процессы и мешать другим, пользователь — один на всех.
Примечания * © Tim Minchin, Lullaby http://habrahabr.ru/post/199202/
|