Котик Как то раз появилась следующая задача: создать локального пользователя в ОС 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"

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

Надеюсь данная информация будет полезной.

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


  1. nApoBo3
    27.01.2019 17:36

    Не очень понимаю как это ограничивает права пользователя и зачем это вообще может быть нужно?
    Разве что для создания ограниченных шелов для младшего ит персонала.


    1. KeyMan Автор
      27.01.2019 21:05

      Примеры использование:
      — дать доступ к системе людям со стороны, что бы не сломали и можно было контроллированно ограничить их действия
      — передача настроенной системе пользователям, что бы могли ее использовать и не сломали (ограничить доступ к критическим файлам и директориям)

      Данная задача возникает, если мы считаем что пользователь системы может ее сломать)


      1. nApoBo3
        27.01.2019 23:14
        +2

        Проблема в том, что ваш способ вообще ничего не ограничивает. К безопасности он не относиться никаким боком.
        Я даже не знаю как корректно объяснить. Это не безопасность. Вы никак не ограничили права пользователя в системе, вы настроили, даже не безопасность, а интерфейс шела, примерно как удалить все ярлыки с рабочего стола и считать, что теперь все в безопасности.
        Можно сказать, это один из вариантов UAC или SU( хотя сравнение не корректное, там все таки ограничения безопасности ), чтобы случайно чего-то не поломать, не более того.
        Возможно это имеет смысл, чтобы дать не сильно квалифицированному пользователю возможность запустить самостоятельно ping на сервере который стоит у него в помещении и прочитать вывод администратору. Но для таких задач можно например использовать веб странички с небольшим кол-во команд, и вообще не давать пользователю логиниться на сервере.
        Любой человек обладающий минимальной квалификацией и имеющий желание выйти из вашего окружения сделает это за несколько минут, ну может не минут, но не более получаса.
        Самый простой вариант, ваш zuser может писать, а значит может залить туда произвольный код и выполнить его, не какой шел в данном случае не задействует.


        1. KeyMan Автор
          28.01.2019 00:09
          -1

          Согласен, изначально идея была дать оболочку которая ничего не умеет и только после этого добавлять в нее инструменты и тут кроется камень преткновения безопасности — эти инструменты пользователь может использовать для выхода за пределы оболочки.
          т.е. Для пользователя создана металлическая коробка и он в нее помещен, но для работы ему нужна болгарка, ты ему ее даешь, и вместо того что бы пилить детали внутри коробки, он начинает пилить саму коробку.


          1. imanushin
            28.01.2019 02:09

            Подходит другая аналогия: чтобы защитить сейф, все подходы к банку Вы сделали в виде лабиринта. В итоге сейф унести все равно можно (в том числе — и на вертолете), а вот людям стало жить сложнее.


            Практический разговор о безопасности системы надо начинать с big bounty: то есть сколько Вы готовы отдать за дыру в системе. Если разработчик бритая пообещать даже малую сумму, то отсюда неутешительный вывод отрельном положении дел.


            И если подытожить — правильнее называть подобное не «ограничение прав», а «защита от дурака». То есть специалист все равно выломает, однако случайный пользователь теперь случайно навредит с меньшей вероятностью.


    1. bano-notit
      27.01.2019 23:01

      Иногда нет возможности использовать ansible shell, приходится использовать прямой доступ по ssh для маленького CD. А чтобы компрометация ssh ничего не дала взломщику, можно максимально ограничит аккаунт.

      Но согласен, легче всё же просто ограничить доступ пользователя исполнением одного единственного неизменяемого скрипта.


  1. BorLaze
    27.01.2019 17:36

    Разве в п.7 должно быть не

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

    ?


    1. KeyMan Автор
      27.01.2019 21:06

      Спасибо, fix


  1. Jouretz
    27.01.2019 17:49
    +8

    Костыли в безопасности — самые опасные среди костылей.
    Если у юзера есть доступ к чему-то из [man, vim, more, less, awk, zip, tar, git...] то он выходит из ваших ограничений. Если нет, не особо понятно, что он там вообще делает? Мб доступ к шелу можно было заменить одной формой или чем-то подобным?


    1. KeyMan Автор
      27.01.2019 21:33

      Спасибо за вопрос, он действителен важен.
      На сколько я знаю основные атаки заключается в следующем:
      изменить переменную PATH
      Для блокировки данной уязвимости мы добавляем alias в файл .bashrc:
      alias set=':'
      alias uset=':'
      alias export=':'
      alias typeset=':'
      alias declare=':'
      alias alias=':'
      alias unalias=':'
      — переход в полноценную оболочку через скрипт или через утилиты vi, vim, nano, awk и т.д
      Так же можно защитится через alias в файле .bashrc:
      alias bin=':'
      alias sh=':'
      alias ln=':'
      — также, для дополнительной защиты все команды через которые можно получить доступ к файлу или выполнить скрипты необходимо делать через обертки (п.8, п.9)

      Если есть еще варианты взлома, напишите пожалуйста.


      1. Jouretz
        27.01.2019 21:47
        +3

        А вы тестили? Я смотрю, у меня vim алиасы не воспринимает.
        image
        :!ll который алиас не отработал
        :!ls — работает
        :!/bin/sh — запускает shell

        Ну и как вариант — атака через ssh
        awk 'BEGIN {system("/bin/sh")}' такая ещё штука. Смотря что у вас там доступно.
        image


        1. KeyMan Автор
          27.01.2019 21:53

          Спасибо большое, посмотрим что можно сделать.


        1. selivanov_pavel
          28.01.2019 00:07
          +2

          Если find доступен, можно с awk и не заморачиваться:


          find . -maxdepth 0 -execdir /bin/bash \;


  1. Sjam
    27.01.2019 17:52
    +5

    Как-то chroot для этих целей кажется проще и уместнее


    1. KeyMan Автор
      27.01.2019 21:47

      Через chroot получается немного другой подход (песочница).


    1. KeyMan Автор
      28.01.2019 13:39

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


      1. arheops
        29.01.2019 00:19

        Все просто. Делаете какойто скрипт который делает chroot, выставляет нужные переменные и запускает shell.
        называете его /bin/chrootedshell
        выставляете пользователю shell в этот скрипт. все.


  1. andreymal
    27.01.2019 18:34
    +2

    Во-первых, уверен, это всё можно обойти, если покопаться повнимательнее.


    Во-вторых, а зачем такой урезанный доступ вообще нужен? У меня не получается придумать практических применений для этого.


    1. tchspprt
      27.01.2019 19:18
      -1

      Как минимум есть одно.
      И на первый, и на второй вопрос ответ — учебный курс по администрированию / инфобезу / etc. Отрестриктить так, чтобы фиксить трабл не получилось с помощью service restart / shutdown now / других нетрушных методов (я надеюсь Вы поняли). А если речь идёт о курсе по инфобезу — то за обход защиты от плюсика в карму до автомата (в зависимости от глубины курса, доброты преподавателя, остальной аудитории).


      1. Jouretz
        27.01.2019 19:39
        +2

        Я, конечно, дико извиняюсь. Но учебный курс teaching to use bad practices это просто bullshit. И если teacher doesn't understand what в информационной безопасности нужно в первую очередь использовать appropriate methods для решения конкретных tasks, то его профпригодность is questionable.


        1. mk2
          27.01.2019 21:06

          Я am очень sorry, но mixing английские words с russian аналогами is плохая practice сама по itself.


          1. Jouretz
            27.01.2019 21:19
            +2

            Шутка повторённая дважды в два раза смешнее?


            1. mk2
              27.01.2019 21:22

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


        1. tchspprt
          27.01.2019 21:41

          Bad practices — то, что ждёт рядового студента в будущем ежедневно. Если говорить о программировании, например, то переписывание легаси-кода — это то, за что с наибольшей вероятностью прошлый студент покупает хлеб. Быть знакомым с врагом заранее — неплохой вариант, вообще-то.


        1. tchspprt
          27.01.2019 22:07

          Так, падажжите… профпригодность is questionable, говорите? То бишь такие вещи придумывают низкоквалифицированные идиоты, которых Вы можете так же тончайше и остроумнейше высмеять, как меня?


      1. keydon2
        27.01.2019 20:58
        +1

        Создать по контейнеру на каждого пользователя и пускай творят что хотят до желаемого результата?


        1. tchspprt
          27.01.2019 21:35

          Не всегда покатит. Я не спец, но похожий на правду пример «непокатимости» могу привести.
          Например, при изучении раздела загрузки ОС — задача на GRUB, нужно изменить ключи загрузки. Тяжело сформулировать конкретную задачу, но можно перекрыть возможность mkinitrd — закрыть простой путь. Да, конкретно в этой задаче содержимое статьи — вряд ли лучший инструмент, достаточно какого-нибудь SELinux, наверное. Но в общем в любом случае задача, в которой инструмент встанет, может всплыть.


          1. etho0
            28.01.2019 13:12

            Целый инструмент для одной задачи многовато будет. А для большего количества он уже не подходит… Да и изменять GRUB на рабочей машине это чет совсем странно. Чем вам виртулка не нравиться?


            1. tchspprt
              28.01.2019 15:56

              Виртуалка да, но не контейнер. LXD тут не покатит)


    1. KeyMan Автор
      27.01.2019 21:51

      1. Скорей всего, все можно обойти) По тем способам, которые я знаю мы немного защитились, а по остальным нужно смотреть

      2. Примеры использование:
      — дать доступ к системе людям со стороны, что бы не сломали и можно было контроллированно ограничить их действия
      — передача настроенной системе пользователям, что бы могли ее использовать и не сломали (ограничить доступ к критическим файлам и директориям)

      Данная задача возникает, если мы считаем что пользователь системы может ее сломать)


      1. dimkrayan
        28.01.2019 10:34
        +1

        точно защитились? Может, вы просто не знаете, что не защитились?


    1. TheShock
      28.01.2019 06:38

      2) Школьников линуксу учить?


  1. skymal4ik
    27.01.2019 18:56
    +1

    Был у меня похожий заказчик.

    Хотел, чтобы люди, работающие по vpn по RDP из дома на 1С-сервере не могли шарить друг с другом файлы и вообще не знали о существовании других пользователей. И чтобы у каждого пользователя минимум прав и отчёты получать кто что сделал.

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

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

    У вас нету варианта дать человеку виртуалку и пушить работу в гит/вики или вызывать скрипты через веб, например?


    1. ni-co
      27.01.2019 19:11

      А, что они у Вас по RDP сразу в программу 1 С не входят?
      Жесткий сценарий входа.


    1. KeyMan Автор
      27.01.2019 22:01

      Задача передать готовую систему, что бы пользователь мог ее контролировать и выполнять минимальные действия. Дело в том, что уровень знания пользователя неизвестен и он может что-то сломать. Искать что он сломал трудоемко, быстро починить можно только откатив систему, что бы минимизировать данные риски решили урезать возможности пользователю.


      1. hokum13
        28.01.2019 13:53

        Я чего-то не понимаю:
        а что мешает пользователю дать просто урезанную учетку — не рута. Он же и так мало что сможет. «От дурака» это спасет. А от квалифицированного хакера, который не просто скрипт-кидди и отдельная_виртуалка/chroot/контейнер не факт что защитит.

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


  1. mk2
    27.01.2019 19:13

    А если не секрет — зачем в этих ограничениях отрублено автодополнение?


    1. nApoBo3
      27.01.2019 20:42

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


      1. KeyMan Автор
        27.01.2019 22:03

        Да все верно, выполнив echo /«tab» пользователь увидит структуру каталогов.


  1. Andronas
    27.01.2019 21:20
    -1

    Подобный способ (restricted shell) есть также и в AIX, использую данный способ ограничения для некоторых пользователей уже давно.


  1. arheops
    27.01.2019 21:24
    +2

    Чем вам selinux и chroot то не подошло?

    Напишите список утилит в вашем /home/user/bin, мы вам сообща напишем, как обойти вашу «защиту».

    Вот так обходится ваш блеклист к ls, например(проверил)
    ls /\?in


    1. KeyMan Автор
      27.01.2019 22:10

      Очень интересно, согласен что 100% защиты конечно же нет, но Ваш пример добавим в blacklist.
      Спасибо.


      1. Sap_ru
        27.01.2019 22:41
        +3

        Вы не сможете соcтавить нормальный black-list — слишком много способов. И по мере обновления системы будут появляться новые. Сам способ уже очень кривой.


        1. KeyMan Автор
          27.01.2019 22:50

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


          1. arheops
            28.01.2019 00:33
            +3

            Это фигня. Либо вы делаете whitelist либо ничего не делаете.
            Существуют миллиарды комбинаций, шел сильно мощная штука.
            Все уже придумано до вас, используйте chroot.
            Если вам в chroot надо чтото прокинуть — используйте pipes/hardlinks.


            1. KeyMan Автор
              28.01.2019 10:47
              -2

              один whitelist лист, к сожалению не поможет, можно использовать такую комбинацию:
              cat /home/zuser/../../etc/passwd
              Данную угрозу можно конечно снизить совместив blacklist и whitelist, но как Вы правильно заметили, всех возможностей учесть достаточно сложно.


              1. Sap_ru
                28.01.2019 18:18

                Вы сначала рута получите для таких фокусов (не говоря о том, что конкретно ваша команда давно уже не работает таким образом).
                А если у вас рут есть, то вам уже ничего большле не нужно. И уж точно никакой restricted шел рута не остановит никогда. Тут только всякие SELinux.


          1. Sirikid
            28.01.2019 18:51

            Зачем тогда было писать статью?


      1. arheops
        28.01.2019 07:43

        Ну вот вы добавили в блеклист.
        Давайте дальше, чтоли «добавляйте»
        ls /\[b\]in
        ls /\[a-z\]in
        ls /\[a-b\]in
        ls /\*in

        Логичнее было добавить обратный слеш, но есть еще другие варианты.
        И это только один вид атак — регекспы.


  1. Sap_ru
    27.01.2019 22:40
    +7

    Зашибись безопасность!
    Извените, но этот подход совершенно бесполезен. Тут сходу десякти способов запустить полноценный шелл можно придумать. А если вы начнёте эти способы ограничивать (через chroot, права, ещё что-то), то на фига этот недо-шелл вообще нужен?


    1. KeyMan Автор
      27.01.2019 22:48

      Да действительно он не обеспечивает 100% защиту. Статья немного изменила вектор: инструкция превратилась в анализ безопасности данного способа, что очень важно.


      1. tchspprt
        28.01.2019 00:36

        Не считается, так как Вы это не подразумевали при публикации статьи. :)


    1. tyderh
      28.01.2019 02:05
      +3

      Да. Вредная статья. Мне как-то давали подобный rbash, чтобы я не лазил где попало. Даже обходить ничего не пришлось, залил при помощи scp нормальный шелл в одну из разрешенных утилит и вперед, лол.


  1. selivanov_pavel
    28.01.2019 00:16

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


    1. arheops
      28.01.2019 00:33

      Для этого достаточно младшему персоналу PATH переопределить.


  1. funca
    28.01.2019 01:53
    +1

    Был у нас заказчик как раз с такой фигнёй на серверах. Все понимал, но ни как не мог повлиять на тамошних админов, нагородивших этот странный огород. Сошлись на том, что кастыль для доступа к командам shell через консольный mysql вкрутили даже в ansible.


  1. KonstantinSpb
    28.01.2019 11:51

    Можеть лучше SELinux настроить?


  1. inkvizitor68sl
    28.01.2019 15:06
    +1

    Правильный ответ — jailkit.
    Rbash действительно дырявенький с этой точки зрения. Ну то есть сам по себе rbash хорош и задачу (свою!) выполняет, но его задача — не совсем в области безопасности, а как верно замечают выше — скорее, чтобы у неопытных пользователей консоли глаза от обилия бинарников не разбегались.


  1. jenki
    28.01.2019 23:21

    использование сторонних утилит, например SELinux (не подошло, усложняет систему)

    useradd -c «User with the limited rights» -Z guest_u -m -U -s /bin/bash user
    passwd user

    Вот весь SELinux


  1. POPSuL
    30.01.2019 02:21
    +1

    И конечно же забыли про LD_PRELOAD...