UMGUM.COM (лучше) 

Linux + check permisions ( Простая проверка доступности ресурсов файловой системы для непривилегированного пользователя. )

27 января 2013  (обновлено 27 мая 2017)

OS: Linux Debian Lenny/Squeeze.
Application: Linux Bash v.4 (Bourne again shell).

Задача: удостоверится в корректности применения разрешений на доступ к ресурсам файловой системы сервера для сервисов запускаемых от имени непривилегированных пользователей.

Везде и всегда (даже когда это не особо нужно) я стараюсь запустить сервисы от имени пользователя, обладающего минимальными правами в системе. Если возможно заключить сервис в "chroot" - делаю это. В детстве я увлекался книжками о приключениях, неотъемлемой составляющей которых разного рода проникновения (спасаем от дракона принцессу, пробираемся на секретную базу противника), возможно с тех пор внутри сидит необходимость контролировать окружающее пространство на предмет усложнения доступа к своим ресурсам (я не плохой, но всё относительно). Естественно, объявления правил безопасности мало - нужно периодически контролировать состояние дел и проверять эффективность принятых мер.

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

В своё время мною были написаны "на коленке" множество всяких "проверяльщиков", но вот сейчас я как-то взялся и оформил небольшой скрипт, запустив который можно найти все доступные определённому пользователю ресурсы файловой системы:


# touch /usr/local/bin/сhafsr.sh
# chmod u+x /usr/local/bin/сhafsr.sh

#!/bin/bash

echo "Custom check the availability of file system resources."

USER=$1
POINT=$2
TYPE=$3

# Check incoming variables
[ -z "${USER}" -o -z "${TYPE}" -o -z "${POINT}" ] && { echo "Usage $0 username path {dir|file}"; exit 1; }
[ `grep --ignore-case --count "^${USER}:" /etc/passwd` -eq 0 ] && { echo "Username \"${USER}\" not found."; exit 1; }
[ ! -e "${POINT}" ] && { echo "Path \"${POINT}\" not found."; exit 1; }
if [ "${TYPE}" = "dir" ]; then
  TYPE="d"
  echo; echo "Check availability to user \"${USER}\" directories (only directories)."
else
  if [ "${TYPE}" = "file" ]; then
    TYPE="f"
    echo; echo "Check availability to user \"${USER}\" files (not directories, only files)."
  else
    echo "Specify the type of search objects in the third argument: {dir|file}."
    exit 1
  fi
fi

echo; echo "Next items is readable for user ${USER}:"
find ${POINT} \( -path '/dev/*' -o -path '/sys/*' -o -path '/proc/*' \) -prune -o -type ${TYPE} -print0 | xargs --null --no-run-if-empty -I {} su --shell /bin/bash --login ${USER} --command "test -r '{}' && echo 'readable: {}'" 2>/dev/null

echo; echo "Next items is writable for user ${USER}:"
find ${POINT} \( -path '/dev/*' -o -path '/sys/*' -o -path '/proc/*' \) -prune -o -type ${TYPE} -print0 | xargs --null --no-run-if-empty -I {} su --shell /bin/bash --login ${USER} --command "test -w '{}' && echo 'writable: {}'" 2>/dev/null

exit 0

Где:

"( -path ’/dev/*’ -o -path ’/sys/*’ -o -path ’/proc/*’ ) -prune" - набор директив утилиты "find", предписывающий пропустить перечисленные ресурсы;
"-o" - модификатор утилиты "find", предписывающий продолжать отработку правил следующих далее только в случае неуспеха предыдущих;
"-type" - директива утилиты "find", ограничивающая поиск типом ресурсов;
"-print0" - директива утилиты "find", предписывающая формировать вывод в виде строк, завершая из специальным символом "null character";
"--null" - директива утилиты "xargs", предписывающая разбирать входящий поток на строки, не по пробелам и символам табуляции, как обычно, а по специальному символу "null character";
"-I {}" - директива утилиты "xargs", явно предписывающая подставлять далее обрабатываемые аргументы в место обозначенное сочетанием символов "{}" (это сочетание произвольное, фигурные скобки были выбраны исходя из малой вероятности их применения в таком виде для других целей);
"su .... --command" - строка инициируемая на исполнение утилитой xargs, в пространство переменных которой передаются аргументы, полученные от утилиты "find";
"test -w ’{}’" - тест на возможность чтения или записи применительно к проверяемым ресурсам файловой системы.

Учитывая то, что для каждого проверяемого объекта файловой системы запускается на исполнение "оболочка" bash, в которой проводится тест как таковой, в целом процедура не быстрая. Однако надёжная.

Я встречал другие варианты проверки, более упрощённые, преследующей аналогичные цели. Например такой (на http://habrahabr.ru/):

su --shell /bin/bash --login www-data --command "find / \( -path '/dev/*' -o -path '/sys/*' -o -path '/proc/*' \) -prune -o -type d -writable -print0 | xargs --null --no-run-if-empty printf '%s\n'" 2>/dev/null

В комментариях к заметке (http://habrahabr.ru/post/164245/) описывающей этот способ проверки последовало несколько уточнений, но никто не обратил внимание на один немаловажный фактор, сводящий на нет смысл проверки сервера, настройка безопасности которого сложнее принятой "по умолчанию".

Суть в том, что в обсуждаемом "хабровском" варианте проверки перебор объектов ведётся от имени непривилегированного пользователя. В таком случае, наткнувшись на виртуальный корень файловой системы изолированного в "chroot" сервиса, утилита "find" получит отказ в доступе и не пойдёт глубже. Однако, "chroot" для того и делается, чтобы не дать войти в него и выйти из него непривилегированным сервисам, что не отменяет внутри него сложной системы разрешений доступа для изолированных там пользователей. Вот эту саму систему разрешений в "chroot" "хабровский" способ проверить не сможет - это серьёзный недостаток.


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )