Linux Capabilities
Max Alexeev (@wi_max)
Ни для кого не секрет, что некоторые действия мы можем выполнить только обладая правами суперпользователя, однако, существуют определенные механизмы, позволяющие воспользоваться такими правами лишь в данном контексте, ведь мы хотим следовать принципу минимальных привилегий, в конце концов или нет? Действительно, для достижения подобной функциональности система позволяет осуществить настройку sudo для конкретного пользователя, а также указать setuid для некоторых исполняемых файлов, что позволит выполнить их от имени владельца. Однако, не всегда такой подход является безопасным, а главное, система позволяет использовать еще более «тонкую» настройку за счет механизма, называемого Capabilities (возможности - по ходу статьи я буду придерживаться этой терминологии).
Что же такое эти Capabilities?
Традиционно, UNIX систему можно рассматривать, как систему в котором процессы исполняются в двух контекстах: привилегированный пользователь, чей UID обычно равен 0 и непривилегированный – все остальные. Механизм возможностей позволил разделить все процессы на блоки, в зависимости от того, какие ресурсы ядра (привилегии) им необходимы. Простейший пример, который можно привести описывает следующая задача. Нам необходимо, чтобы веб-сервер прослушивал 80 порт, ожидая подключения, но как это сделать, учитывая, что для прослушивания портов <1024 необходимы привилегии суперпользователя? Отличное решение – позволить веб-серверу использовать привилегии суперпользователя в части касающейся сетевого взаимодействия, установив CAP_NET_BIND_SERVICE.
Ниже приведу расширенный список возможностей, отдельно обратите внимание на номер 7, он нам потом понадобится:

Таким образом, использование той или иной возможности в рамках определенной задачи, обеспечивает точечное выделение привилегий.
Capabilities в действии!
Для того чтобы получить информацию об установленных возможностях для исполняемого файла воспользуемся утилитой getcap. Синтаксис команды следующий:
getcap <path_to_executive_file>
Отличный пример, который можно привести – команда ping:

Команде необходимо использование сокетов для отправки ICMP пакетов и мы ей предоставляем данные возможности. Закономерный вопрос, а что за ep после знака равно?
Все очень просто, для каждой возможности доступны 3 состояния:
- e: Effective – означает, что данная capability активна;
- p: Permitted – означает, что данная capability разрешена;
- i: Inherited – означает, что данная capability будет наследоваться дочерними процессами.
Последнее, что стоит понимать, как устанавливать и удалять возможности. По аналогии с getcap, существует утилита setcap (необходимы права суперпользователя):
sudo setcap <capability>+e <path_to_executive_file>
Стоит отметить, что для установления возможности используется +, для того, чтобы забрать данные привилегии – (здесь по аналогии с chmod). Также, мы можем сами выбирать и комбинировать необходимые состояния (e,p,i).

С помощью этой команды мы забрали возможность у нашего ping, проверяем:

Вернем все в прежнее состояние:

Вот таким нехитрым способом мы можем ограничить использование привилегированных ресурсов.
Повышаем привилегии
К чему я это все, спросите вы? Давайте вернемся к списку возможностей, помните я говорил о номере 7?
CAP_SETUID – позволяет изменять UID на необходимый.
То есть, если у нашего исполняемого файла есть данная возможность, мы можем его исполнить от имени любого пользователя в системе (и от суперпользователя тоже, да-да). Допустим, получили мы доступ к удаленному хосту и обнаружили, что python3 работает с CAP_SETUID, разумеется, мы имеем безоговорочный вектор повышения привилегий:

Попробуем проэксплуатировать привилегии и запустить шелл, предварительно установив UID в 0 (root):

БАМ! И мы имеем привилегии суперпользователя.
Несмотря на то, что механизм возможностей позволяет предоставить точечные привилегии, стоит использовать его внимательно и осторожно, понимая, какие последствия могут быть. Что касается атакующих, то это еще одна возможность компрометации системы в их копилку.