Данная функция очень опасна: она вызывает оболочку для выполнения команды,
переданной ей как аргумент. Поведение оболочки зависит от желания пользователя.
Типичный пример возникает при рассмотрении переменной окружения
PATH. Посмотрим на приложение вызывающее команду mail.
Например, следующая программа посылает свой исходный код пользователю, который
ее запустил:
/* system1.c */
#include <stdio.h>
#include <stdlib.h>
int
main (void)
{
if (system ("mail $USER < system1.c") != 0)
perror ("system");
return (0);
}
Предположим, эта программа Set-UID root :
>> cc system1.c -o system1
>> su
Password:
[root] chown root.root system1
[root] chmod +s system1
[root] exit
>> ls -l system1
-rwsrwsr-x 1 root root 11831 Oct 16 17:25 system1
>>
Чтобы выполнить эту программу, система запускает оболочку
(/bin/sh) с опцией -c, опция сообщает ей инструкцию
для запуска. Затем, оболочка проходит через иерархию каталогов в соответствии с
переменной окружения PATH, чтобы найти выполняемый файл, который
называется mail. Чтобы скомпрометировать программу, пользователю
достаточно поменять значение этой переменной перед запуском приложения.
Например:
>> export PATH=.
>> ./system1
ищет команду mail только в текущем каталоге.
Достаточно создать выполняемый файл (например скрипт, запускающий командный
процессор) и назвать его mail, и программа будет затем запущена с
EUID-ом владельца основного приложения! Здесь наш скрипт запускает
/bin/sh. Однако, так как он запустился с перенаправленным
стандартным входом (как начальная команда mail), мы должны вернуть
его на терминал. Создаем скрипт:
#! /bin/sh
# "mail" script running a shell
# getting its standard input back.
/bin/sh < /dev/tty
Конечно, первое решение состоит в указании полного пути к программе, например
/bin/mail. Тогда возникает новая проблема: местоположение
приложения зависит от установки системы. Если /bin/mail обычно есть
на любой системе, то например где находится GhostScript? (может он в
/usr/bin, /usr/share/bin,
/usr/local/bin?). С другой стороны, еще один тип атаки возможен при
использовании некоторых старых оболочек: использование переменной окружения
IFS. Оболочка использует ее при разборе слов в командной строке.
Эта переменная содержит разделители. По умолчанию это пробел, табуляция и
возврат каретки. Если пользователь добавит туда слэш /, команда
"/bin/mail" будет понята оболочкой как "bin mail".
Выполняемый файл, который называется bin, в текущем каталоге может
быть выполнен всего лишь установкой переменной PATH, как мы видели
ранее, что позволит запустить эту программу с EUID приложения.
Под Linux переменная окружения IFS - уже не проблема, с тех пор
как bash и pdksh закрыли ее используя символы по умолчанию при запуске. Но помня
о переносимости приложения, вы должны знать, что некоторые системы могут быть
менее безопасными относительно этой переменной.
Некоторые другие переменные окружения могут вызвать неожиданые проблемы.
Например, приложение mail позволяет пользователю выполнить команду
при написании сообщения используя управляющую последовательность
"~!". Если пользователь пишет "~!command" в
начале строки, команда выполняется. Программа /usr/bin/suidperl,
используемая для запуска скриптов perl с битом Set-UID, вызывает
/bin/mail, чтобы отправить сообщение root-у при
обнаружении проблемы. Так как /usr/bin/suidperl Set-UID
root, вызов /bin/mail происходит с привилегиями root и
содержит имя файла, который вызвал ошибку. Тогда пользователь может создать
файл, имя которого содержит возврат каретки с последующим ~!command
и еще одним переводом. Если perl скрипт вызываемый suidperl
аварийно завершает работу из-за низкоуровневой проблемы, относящейся к этому
файлу, посылается сообщение от root, которое содержит управляющую
последовательность приложения mail, и команда из имени файла
выполняется с правами root.
Этой проблемы не существует, так как программа mail не допускает
приема управляющих последовательностей при автоматическом выполнении (не с
терминала). К сожалению, недокументированная возможность данного приложения
(вероятно оставшаяся от отладки) допускает управляющие последовательности, если
установлена переменная окружения interactive. Результат? Дырой в
безопасности можно легко воспользоваться (и широко используется) в приложении,
которое должно улучшать безопасность системы. Ответственность за это разделена.
Первое, /bin/mail содержит недокументированную опцию особенно
опасную, т.к. она позволяет выполнение кода, проверяя только посылаемые
данные, что должно быть априори подозрительным для почтовой
утилиты. Второе, даже если разработчики /usr/bin/suidperl не знали
о переменной interactive, они не должны были при вызове внешней
команды оставлять окружение выполнения таким же, каким оно и было, особенно
делая эту программу Set-UID root.
Фактически Linux игнорирует биты Set-UID и Set-GID при выполнении скриптов
(см. /usr/src/linux/fs/binfmt_script.c и
/usr/src/linux/fs/exec.c). Но хитрыми действиями можно обойти это
правило, как делает Perl со своими скриптами используя
/usr/bin/suidperl, чтобы принять к сведению эти биты.