В двух предыдущих статьях (часть 1, часть 2) мы рассмотрели различные аспекты правления учетными записями и настройки доступа к файлам. Однако, при настройке доступа всегда можно ошибиться, задав неверные значения. Если администратор выдал недостаточные права, то такая ошибка будет найдена довольно быстро, так как, тот кому этих прав не хватит очень скоро пожалуется админу. Но что делать, если прав в итоге оказалось больше, чем нужно? Многие, конечно, могут сказать, что это вообще не проблема, мол больше не меньше, но на самом деле это ошибочная логика. Как мы увидим в сегодняшней статье, даже безобидные на первый взгляд разрешения могут привести к получению прав root в системе.

При этом, стоит помнить, что даже опытный администратор может ошибиться, предоставив лишние права. Поэтому всегда следует помнить принцип наименьших привилегий. Назначайте пользователям только те права, которые им действительно необходимы, не больше.

Исходные данные

Перед тем, как начать обсуждение хакерских методов, нам необходимо договориться о том, что у нас будет на старте. Итак, предположим, что вы являетесь администратором серверов Linux, с которыми работают различные пользователи: программисты, инженеры, тестировщики. Всем им в том или ином виде необходим доступ в консоль на различных серверах и определенные наборы прав: одни работают со скриптами и планировщиком crontab, другие с контейнерами docker, а третьи компилируют и отлаживают код. Но ни у кого из этих пользователей нет прав root.

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

Эскалируй это

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

Но как часто бывает, после выполнения этой срочной задачи, администратор не стал снова править файл /etc/sudoers, в результате чего, программист смог и дальше запускать git под sudo без пароля.   

Когда злоумышленникам удалось получить доступ к машине программиста, они смогли попасть на Linux сервер. Узнав, что для git разрешен запуск под sudo, хакер выполнил следующие команды  

sudo git help config

!/bin/sh

И получил root. При выполнении git можно получить доступ к командной строке с правами текущего пользователя. Так как команда была запущена под sudo, полученный shell оказался root.

Пользователь инженер постоянно пишет скрипты и правит конфиги с помощью редактора nano. Для доступа к некоторым системным каталогам он попросил дать sudo для работы с nano.

Файл, скачанный инженером из очень недоверенного источника и запущенный на своей машине, позволил хакеру получить туда доступ, а затем и на сервер.

Для эскалации сначала запускаем sudo nano, затем Ctrl+R и Ctrl+X, оказываемся в командной строке и выполняем

reset; sh 1>&0 2>&0

Также получаем root shell.

Тестировщик часто пользовался командой find, и его очень раздражало, что при попытке обращения к некоторым каталогам команда возвращала Permission Denied. Так он получил sudo на find. А хакер получив доступ на его машину, просто подсунув тестировщику специально собранный файл с машины программиста. Для получения root shell необходимо просто выполнить команду с ключом для запуска оболочки.

sudo find . -exec /bin/sh \; -quit

На этих несложных, но жизненных примерах мы рассмотрели получение прав root с помощью стандартных команд, имеющих права sudo.

Злой SUID

Напомним, что такое SUID bit. Это специальный бит, который позволяет выполнение программы с правами хозяина файла. Для его установки необходимо под root выполнить команду

chmod u+s файл_shell.

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

cp /bin/sh /bin/sys_sh

chmod u+s /bin/sys_sh

Первая строка копировала легальный шелл /bin/sh в некий sys_sh, а вторая присваивала sys_sh SUID bit. Когда через некоторое время один из “пропатченных” скриптов был запущен, создался файл /bin/sys_sh который после запуска открывал оболочку root.

На другом сервере злоумышленник использовал аналогичный сценарий но с переменной PATH, только теперь он рассовал скрипты с одинаковыми названиями в различные каталоги.

Незапланированный cron

Планировщик crontab является удобным средством выполнения задач по расписанию в ОС Линукс. По сути, cron это классический Unix daemon , использующийся для периодического выполнения заданий в определенное время. При этом,  задания хранятся в специальных файлах в определенном формате, поддерживается возможность запуска заданий от имени разных пользователей.

Зайдя на один из серверов под пользовательским аккаунтом злоумышленник выполнил следующую команду:

find / –type f -path /sys -prune -o -path /proc -prune -o -user root -perm -4000

Эта команда ищет файлы, на которые установлен SUID bit 04000 - (s-бит) выполнение с правами владельца файла. Также в логах было найдено упоминание работы скрипта backup.sh, который имел SUID bit, и при этом его мог редактировать данный пользователь.

Тогда наш хакер решил заполучить выполнимый файл, после запуска которого он получит права root. Для этого ему потребуется следующий код на языке С:

#include <unistd.h>

int main()

{

setreuid(geteuid(),geteuid());

execve("/bin/sh",0,0);

}

Данный код получает эффективный UID и затем с этим идентификатором открывает командную строку. Но проблема заключается в том, что нашему хакеру необходимо, чтобы этот выполнимый файл должен быть собран под root и ему должен быть назначен SUID bit. То есть необходимы выполнить следующие команды:

gcc suid.c -o /bin/backdoor

chmod u+s /bin/backdoor

Но мы помним про файл скрипта, который выполняется в crontab под root, и в который может вносить изменения любой пользователь. Злоумышленник просто добавляет в этот скрипт несколько строк, которые сначала создают во временном каталоге файл с исходным кодом на С, который затем компилируется и получает SUID bit. 

#!/bin/bash

echo "" > /tmp/suid.c

echo "#include <unistd.h>" >> /tmp/suid.c

echo "int main()" >> /tmp/suid.c

echo "{" >> /tmp/suid.c

echo "setreuid(geteuid(),geteuid());" >> /tmp/suid.c

echo 'execve("/bin/sh",0,0);' >> /tmp/suid.c

echo "}" >> /tmp/suid.c

gcc /tmp/suid.c -o /bin/backdoor

chmod u+s /bin/backdoor

Теперь для получения root shell достаточно просто запустить файл /bin/backdoor.

Побег из контейнера

На одном из серверов программист попросил sudo для запуска контейнеров docker. Когда злоумышленник попал на этот сервер, он подгрузил контейнер с Linux, из которого получил root для системы на основной машине.

docker run -v /:/mnt –rm -it alpine chroot /mnt sh

… и обновиться не забудь

Во время настройки одного из серверов права sudo предоставили инженеру для обновления софта. Потом, этому серверу закрыли доступ в интернет, а вот забрать права забыли. В результате, злоумышленник запустил apt-get с ключом Pre-Invoke, который выполняет действия до начала загрузки обновлений и которому вообщем-то неважно отсутствие доступа в интернет.

Root shell был получен с помощью следующей команды:

sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh

Заключение

Мы рассмотрели целый набор типовых ошибок при настройке прав доступа в Линукс. Что можно было бы посоветовать для минимизации рисков поднятия привилегий. Там где это допустимо, можно ограничить выполнения команд, разрешив выполнение только без аргументов. Для этого в /etc/sudoers необходимо указать после команды пустые кавычки. Вот пример для ls.

user1   ALL=(root)      /usr/bin/ls “”

Также очевидным решением является ревизия всех пользователей у кого есть sudo и выяснение, действительно ли ему нужны админские права для запуска данных команд.

Для получения полного списка команд, аргументы которых позволяют открыть шелл совершенно необязательно часами шерстить man. Узнать эти команды с примерами эксплуатации можно на сайте https://gtfobins.github.io/

Для борьбы с SUID воспользуйтесь следующей командой:

 sudo find / –type f -path /sys -prune -o -path /proc -prune -o -user root -perm -4000

В результате ее выполнения вы получите список всех файлов, имеющих SUID bit. Их будет довольно много и большинство из них будут системными, но к тем, что окажутся в пользовательских каталогах, необходимо присмотреться повнимательнее.

Также необходимо провести аудит прав доступа к различным скриптам, особенно к тем, что выполняются crontab из под root. У пользователей не должно быть возможности вносить изменения в такие файлы.

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

 В целом же, помимо имеющихся в самой операционной системе механизмов защиты можно также прибегнуть к наложенным средствам, таким как системы мониторинга событий SIEM, системы контроля действий пользователей PAM и другим анализаторам подозрительных
активностей и средствам защиты.

Вместо заключения хочу пригласить вас на бесплатные демоуроки по Linux от OTUS. Зарегистрироваться на уроки можно по ссылкам ниже:

Комментарии (2)


  1. unwrecker
    06.10.2022 23:34

    ... или программный файрвол. Всё же лучше ограничивать, а не мониторить.


  1. saboteur_kiev
    07.10.2022 04:47

    Во всех случаях - грубейшая ошибка настройки, которой в дефолтно настроеном линуксе нет.
    То есть или ты умышленно даешь кому-то судо, или умышленно делаешь что-то от рута, что доступно обычному пользователю.

    С незапланированным кроном непонятно зачем такие сложности. Зачем там создавать какое-то приложение,компилировать его, если можно опять таки банально suid на /bin/sh