it-swarm-ru.tech

Разрешить 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

Однако это относится только к исполняемым файлам; Скрипты оболочки игнорируют бит 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, чтобы избежать запроса пароля. Основным недостатком этого является необходимость записи sudoers каждый раз, когда я хочу это сделать, и необходимость для вызывающей стороны Sudo some-script вместо просто some-script

195
Michael Mrozek

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

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


Сетуид Шебанг

Существует тип гонки, свойственный способу реализации Шебанга (#!):

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

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

Одним из способов защиты этой реализации было бы то, чтобы ядро ​​блокировало файл сценария до тех пор, пока интерпретатор не откроет его (обратите внимание, что это должно предотвратить не только удаление или перезапись файла, но также переименование любого каталога в пути). Но 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]) И выполняет интерпретатор.

Страница Шебанга Свена Машика содержит много информации о Шебанге в разных отделениях, включая поддержка setuid .


Сетуид переводчики

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

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

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

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

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

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

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


TL, DR:

  • Сетуид Шебанг небезопасен, но обычно его игнорируют.
  • Если вы запускаете программу с привилегиями (либо через Sudo, либо через setuid), пишите собственный код или Perl или запускаете программу с оболочкой, которая дезинфицирует среду (например, Sudo с опцией env_reset).

¹ Это обсуждение в равной степени применимо, если вы замените "setgid" на "setuid"; они оба игнорируются ядром Linux в сценариях

213

Одним из способов решения этой проблемы является вызов сценария Shell из программы, которая может использовать бит setuid.
Это что-то вроде Судо. Например, вот как вы могли бы сделать это в программе на 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  

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

57
Hemant

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

#!/bin/sh
[ "root" != "$USER" ] && exec Sudo $0 "[email protected]"

Обратите внимание, что здесь не используется setuid, а просто выполняется текущий файл с Sudo.

24
rcrowley

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

  #!/ust/bin/env sh

  Sudo /usr/local/scripts/your_script

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

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

Обратите внимание, что Sudo обеспечивает некоторую проверку работоспособности, но этого недостаточно - проверяйте каждую строку в своем собственном коде.

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

12
Maciej Piechotka

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

Super позволяет указанным пользователям выполнять сценарии (или другие команды), как если бы они были пользователем 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

5
Nizam Mohamed

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

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

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

4
wzzrd

Если по какой-то причине Sudo недоступно, вы можете написать тонкий скрипт-обертку на C:

_#include <unistd.h>
int main() {
    setuid(0);
    execle("/bin/bash","bash","/full/path/to/script",(char*) NULL,(char*) NULL);
}
_

И как только вы скомпилируете его, установите его как setuid с _chmod 4511 wrapper_script_.

Это похоже на другой опубликованный ответ, но запускает сценарий с чистой средой и явно использует _/bin/bash_ вместо оболочки, вызываемой system(), и поэтому закрывает некоторые потенциальные дыры в безопасности.

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

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

2
Chris