Разрешить setuid для сценариев оболочки

Бит разрешения setuid сообщает Linux, что он запускает программу с эффективным идентификатором пользователя, а не исполнителем:

 > cat setuid-test.c #include <stdio.h> #include <unistd.h> int main(int argc, char** argv) { printf("%d", geteuid()); return 0; } > gcc -o setuid-test setuid-test.c > ./setuid-test 1000 > sudo chown nobody ./setuid-test; sudo chmod +s ./setuid-test > ./setuid-test 65534 

Однако это относится только к исполняемым файлам; shell-скрипты игнорируют бит setuid:

 > cat setuid-test2 #!/bin/bash id -u > ./setuid-test2 1000 > sudo chown nobody ./setuid-test2; sudo chmod +s ./setuid-test2 > ./setuid-test2 1000 

Википедия говорит :

Из-за повышенной вероятности недостатков безопасности многие операционные системы игнорируют атрибут setuid при применении к исполняемым сценариям оболочки.

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

Если нет, существует ли обходное решение этой проблемы? Мое текущее решение состоит в том, чтобы добавить запись sudoers чтобы ALL NOPASSWD запускать данный скрипт в качестве пользователя, которого я хочу запустить, с помощью NOPASSWD чтобы избежать запроса пароля. Основным недостатком этого является необходимость в записи sudoers каждый раз, когда я хочу это сделать, и необходимость того, чтобы вызывающий sudo some-script вместо some-script

  • Многомесячный просмотр в календаре (cal) в OS X
  • Показать каждую установленную оболочку командной строки?
  • команда, которая работает как символ ~ (тильда) для представления некоторого каталога
  • Разбиение файла на две части на основе определенной строки
  • Разделить файл на основе шаблона с ведущими нулями
  • Выполнить строку из сценария оболочки как набор команд оболочки
  • Удаление большого количества файлов
  • Сценарий оболочки, чтобы стать root
  • 7 Solutions collect form web for “Разрешить setuid для сценариев оболочки”

    Linux игнорирует бит setuid¹ во всех интерпретируемых исполняемых файлах (т.е. исполняемые файлы, начинающиеся с строки #! ). Часто задаваемые вопросы в comp.unix.questions объясняют проблемы безопасности с помощью сценариев оболочки setuid. Эти проблемы бывают двух видов: связанные с shebang и связанные с оболочкой; Ниже я расскажу подробнее.

    Если вы не заботитесь о безопасности и хотите разрешить скрипты setuid, под Linux вам нужно будет исправить ядро. Что касается ядер 3.x, я думаю, вам нужно добавить вызов install_exec_creds в функцию load_script , перед вызовом open_exec , но я не тестировал.


    Setuid shebang

    Существует условие гонки, присущее тому, как обычно реализуется shebang ( #! ):

    1. Ядро открывает исполняемый файл и обнаруживает, что он начинается с #! ,
    2. Ядро закрывает исполняемый файл и вместо этого открывает интерпретатор.
    3. Ядро вставляет путь к скрипту в список аргументов (как argv[1] ) и выполняет интерпретатор.

    Если с этой реализацией разрешены скрипты setuid, злоумышленник может вызывать произвольный скрипт, создавая символическую ссылку на существующий скрипт setuid, выполняя его и организуя изменение ссылки после того, как ядро ​​выполнило шаг 1 и до того, как интерпретатор приблизится к открывая свой первый аргумент. По этой причине большинство организаций игнорируют бит setuid, когда они обнаруживают shebang.

    Один из способов защитить эту реализацию – это заставить ядро ​​блокировать файл сценария до тех пор, пока интерпретатор не откроет его (обратите внимание, что это должно предотвращать не только отключение или перезапись файла, но и переименование любой директории в пути). Но unix-системы, как правило, уклоняются от обязательных блокировок, а символические ссылки делают правильную функцию блокировки особенно сложной и инвазивной. Я не думаю, что это так.

    Несколько unix-систем (в основном OpenBSD, NetBSD и Mac OS X, для всех из которых требуется, чтобы параметр ядра был включен) реализовать безопасный setuid shebang с помощью дополнительной функции: путь /dev/fd/ N относится к файлу, уже открытому в файле дескриптор N (поэтому открытие /dev/fd/ N примерно эквивалентно dup( N ) ). Многие системы unix (включая Linux) имеют /dev/fd но не скрипты setuid.

    1. Ядро открывает исполняемый файл и обнаруживает, что он начинается с #! , Допустим, файловый дескриптор для исполняемого файла – 3.
    2. Ядро открывает интерпретатор.
    3. Ядро вставляет /dev/fd/3 список аргументов (как argv[1] ) и выполняет интерпретатор.

    На странице shebang Sven Mascheck есть много информации о shebang через unices, включая поддержку setuid .


    Переводчики Setuid

    Предположим, вам удалось запустить вашу программу под управлением root, потому что ваша ОС поддерживает setuid shebang или потому, что вы использовали собственную бинарную оболочку (например, sudo ). Вы открыли отверстие для безопасности? Может быть . Проблема здесь не в интерпретации vs скомпилированных программ. Проблема заключается в том, что ваша система выполнения работает безопасно, если выполняется с привилегиями.

    • Любой динамически связанный собственный бинарный исполняемый файл интерпретируется динамическим загрузчиком (например, /lib/ld.so ), который загружает динамические библиотеки, необходимые программе. Во многих организациях вы можете настроить путь поиска для динамических библиотек через среду ( LD_LIBRARY_PATH – это общее имя для переменной среды) и даже загружать дополнительные библиотеки во все исполняемые исполняемые файлы ( LD_PRELOAD ). Вызывающий программа может выполнять произвольный код в контексте этой программы, помещая специально созданный libc.so в $LD_LIBRARY_PATH (среди других тактик). Все LD_* системы игнорируют переменные LD_* в исполняемых файлах setuid.

    • В оболочках, таких как sh, csh и производные, переменные среды автоматически становятся параметрами оболочки. С помощью таких параметров, как PATH , IFS и многие другие, вызывающий сценарий имеет множество возможностей для выполнения произвольного кода в контексте сценариев оболочки. Некоторые оболочки устанавливают эти переменные на нормальные значения по умолчанию, если они обнаруживают, что сценарий был вызван с привилегиями, но я не знаю, что есть какая-то конкретная реализация, которой я бы доверял.

    • Большинство сред выполнения (как native, байт-код или интерпретируемый) имеют сходные функции. Немногие принимают специальные меры предосторожности в исполняемых файлах setuid, хотя те, которые запускают собственный код, часто не делают ничего более интересного, чем динамическое связывание (что принимает меры предосторожности).

    • Заметным исключением является Perl . Он явно поддерживает скрипты setuid безопасным способом. Фактически, ваш скрипт может запускать setuid, даже если ваша ОС игнорирует бит setuid в скриптах. Это связано с тем, что perl поставляется с корневым помощником setuid, который выполняет необходимые проверки и повторно выводит интерпретатор на нужные скрипты с требуемыми привилегиями. Это объясняется в руководстве perlsec . #!/usr/bin/suidperl -wT что для скриптов perl для setuid необходимы #!/usr/bin/suidperl -wT вместо #!/usr/bin/perl -wT , но в большинстве современных систем достаточно #!/usr/bin/perl -wT ,

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

    Собственная двоичная оболочка может сделать сценарий оболочки безопасным, если оболочка санирует среду . Сценарий должен заботиться о том, чтобы не делать слишком много предположений (например, о текущем каталоге), но это происходит. Вы можете использовать sudo для этого при условии, что он настроен для дезинфекции окружающей среды. Переменные Blacklisting подвержены ошибкам, поэтому всегда есть белый список. С помощью sudo убедитесь, что env_reset опция env_reset , это setenv выключено, и что env_file и env_keep содержат только безобидные переменные.


    TL, DR:

    • Setuid shebang небезопасен, но обычно игнорируется.
    • Если вы запускаете программу с привилегиями (либо через sudo, либо setuid), напишите собственный код или perl, либо запустите программу с помощью обертки, которая санирует среду (например, sudo с опцией env_reset ).

    ¹ Это обсуждение применяется одинаково, если вы замените «setgid» на «setuid».

    Одним из способов решения этой проблемы является вызов сценария оболочки из программы, которая может использовать бит setuid.
    его что-то вроде sudo. Например, вот как вы могли бы выполнить это в программе на C:

     #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main() { setuid( 0 ); // you can set it at run time also system( "/home/pubuntu/setuid-test2.sh" ); return 0; } 

    Сохраните его как setuid-test2.c.
    компилировать
    Теперь сделайте setuid для этой программы двоичным:

     su - nobody [enter password] chown nobody:nobody a.out chmod 4755 a.out 

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

    Я приписываю несколько скриптов, которые находятся в этой лодке, таким образом:

     #!/bin/sh [ "root" != "$USER" ] && exec sudo $0 "$@" 

    Если вы хотите избежать вызова sudo some_script вы можете просто сделать:

      #!/ust/bin/env sh sudo /usr/local/scripts/your_script 

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

    • Оболочки – это большие части программного обеспечения, которые сильно взаимодействуют с пользователем. Практически невозможно проверить здравомыслие – тем более, что большая часть кода не предназначена для запуска в таком режиме.
    • Скрипты – это, в основном, quick'n'dirty решение и обычно не подготовлены с такой осторожностью, что они позволят setuid. У них много потенциально опасных функций.
    • Они сильно зависят от других программ. Недостаточно проверить оболочку. sed , awk и т. д. необходимо также проверить

    Обратите внимание, что sudo предоставляет некоторую проверку работоспособности, но этого недостаточно – проверьте каждую строку в своем собственном коде.

    В качестве последней заметки: рассмотрите возможность использования возможностей. Они позволяют выполнять процесс, выполняемый как пользовательские привилегии, которые обычно требуют привилегий root. Однако, например, в то время как ping требует управления сетью, ему не нужно иметь доступ к файлам. Однако я не уверен, если они унаследованы.

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

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

    Позвольте мне заявить, что я советую не делать этого. Я просто упоминаю это в образовательных целях 😉

    супер [-r reqpath] команда [args]

    Супер позволяет указанным пользователям выполнять сценарии (или другие команды), как если бы они были root; или он может установить uid, gid и / или дополнительные группы для каждой команды перед выполнением команды. Он предназначен как безопасная альтернатива созданию скриптов setuid root. Super также позволяет обычным пользователям предоставлять команды для выполнения другими; они выполняются с uid, gid и группами пользователей, предлагающих команду.

    Super справляется с файлом “ super.tab '', чтобы узнать, разрешено ли пользователю выполнить запрошенную команду. Если разрешение предоставлено, super будет выполнять pgm [args], где pgm – это программа, связанная с этой командой. (Root разрешено выполнять по умолчанию, но все равно может быть отказано, если правило исключает root. Обычным пользователям запрещается выполнение по умолчанию.)

    Если команда – это символическая ссылка (или жесткая ссылка) тоже на суперпрограмму, то набирать% command args эквивалентно набору% super command args (команда не должна быть супер, или супер не будет распознавать, что она вызывается через ссылка.)

    http://www.ucolick.org/~will/RUE/super/README

    http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html

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

    Он должен быть понятным.

     #include <string> #include <unistd.h> template <typename T, typename U> T &replace ( T &str, const U &from, const U &to) { size_t pos; size_t offset = 0; const size_t increment = to.size(); while ((pos = str.find(from, offset)) != T::npos) { str.replace(pos, from.size(), to); offset = pos + increment; } return str; } int main(int argc, char* argv[]) { // Set UUID to root setuid(0); std::string script = R"(#!/bin/bash whoami echo $1 )"; // Escape single quotes. replace(script, std::string("'"), std::string("'\"'\"'")); std::string command; command = command + "bash -c '" + script + "'"; // Append the command line arguments. for (int a = 0; a < argc; ++a) { command = command + " " + argv[a]; } return system(command.c_str()); } 

    Затем вы запускаете

     g++ embedded.cpp -o embedded sudo chown root embedded sudo chmod u+s embedded 
    Linux и Unix - лучшая ОС в мире.