Linux ігнорує біт setuid¹ для всіх інтерпретованих виконуваних файлів (тобто виконуваних файлів, починаючи з #!
рядка). Comp.unix.questions FAQ пояснює проблеми безпеки з УИП сценаріями оболонки. Ці проблеми бувають двох видів: пов'язані з шебангом і з оболонками; Я розглядаю детальніше нижче.
Якщо ви не дбаєте про безпеку і хочете дозволити встановлені сценарії, під Linux, вам потрібно буде виправити ядро. Щодо ядер 3.x, я думаю, вам потрібно додати дзвінок install_exec_creds
у load_script
функцію до виклику open_exec
, але я не перевіряв.
Сетуїд Шебанг
Існує умова перегонів, властива тому, як #!
звичайно реалізується shebang ( ):
- Ядро відкриває виконуваний файл і виявляє, що воно починається з
#!
.
- Ядро закриває виконуваний файл і замість цього відкриває інтерпретатор.
- Ядро вставляє шлях до сценарію до списку аргументів (as
argv[1]
) та виконує інтерпретатор.
Якщо дозволено встановити сценарії з цією реалізацією, зловмисник може викликати довільний скрипт, створивши символічне посилання на існуючий сценарій встановлення, виконавши його та організувавши змінити посилання після того, як ядро виконало крок 1 і до того, як інтерпретатор обійдеться відкриваючи свій перший аргумент. З цієї причини більшість одноосібників ігнорують встановлений біт, коли виявляють шебанг.
Одним із способів убезпечити цю реалізацію буде ядро, щоб заблокувати файл сценарію до тих пір, поки інтерпретатор не відкриє його (зауважте, що це повинно запобігати не лише від’єднанню або перезапису файлу, а й перейменуванню будь-якого каталогу на шляху). Але системи Unix, як правило, уникають обов'язкових блокувань, і символічні посилання роблять правильну функцію блокування особливо важкою та інвазивною. Я не думаю, що хтось робить це так.
Кілька систем Unix (в основному OpenBSD, NetBSD і Mac OS X, для всіх яких потрібно включити налаштування ядра) реалізують захищений налаштування shebang, використовуючи додаткову функцію: шлях стосується файлу, який уже відкрився в дескрипторі файлу N (тому відкриття є приблизно рівнозначно ). Багато систем Unix (включаючи Linux) мають, але не встановлені сценарії./dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
- Ядро відкриває виконуваний файл і виявляє, що воно починається з
#!
. Скажімо, дескриптор файлу для виконуваного файлу - 3.
- Ядро відкриває інтерпретатор.
- Ядро вставляє
/dev/fd/3
список аргументів (як argv[1]
) і виконує інтерпретатор.
На сторінці шебанга Свена Маскека є багато інформації про shebang через unice, включаючи підтримку налаштування.
Перекладачі-сетуїди
Припустимо, вам вдалося змусити вашу програму запускатися як root, або тому, що ваша ОС підтримує встановлений shebang, або тому, що ви використовували нативну бінарну обгортку (наприклад, sudo
). Ви відкрили отвір для безпеки? Можливо . Питання тут не в тому, щоб інтерпретувати проти складених програм. Питання полягає в тому, чи буде ваша система виконання поводитися безпечно, якщо вона виконується з привілеями.
Будь-який динамічно пов'язаний нативний бінарний виконуваний файл певним чином інтерпретується динамічним завантажувачем (наприклад /lib/ld.so
), який завантажує динамічні бібліотеки, необхідні програмі. У багатьох варіантах ви можете налаштувати шлях пошуку для динамічних бібліотек через середовище ( LD_LIBRARY_PATH
це загальна назва змінної середовища) і навіть завантажити додаткові бібліотеки у всі виконані бінарні файли ( LD_PRELOAD
). Зухвалий програми може виконати довільний код у контексті цієї програми шляхом розміщення спеціально створений libc.so
в $LD_LIBRARY_PATH
(серед інших тактик). Всі здорові системи ігнорують LD_*
змінні у встановленому виконуваному файлі.
У оболонках, таких як sh, csh та похідні, змінні середовища автоматично стають параметрами оболонки. За допомогою таких параметрів, як PATH
, IFS
та багато іншого, виклик сценарію має багато можливостей виконувати довільний код у контексті сценаріїв оболонки. Деякі оболонки встановлюють ці змінні як певні за замовчуванням, якщо вони виявляють, що скрипт викликав привілеї, але я не знаю, що існує якась конкретна реалізація, якій я би довіряв.
Більшість середовищ виконання (будь то рідний, байт-код чи інтерпретований) мають подібні особливості. Мало хто вживає спеціальних заходів обережності для встановлених виконуваних файлів, хоча ті, хто працює з нативним кодом, часто не роблять нічого фантастичнішого, ніж динамічне посилання (що вживає запобіжних заходів).
Perl - помітний виняток. Він явно підтримує встановлені сценарії захищеним способом. Насправді, ваш сценарій може запускати setuid, навіть якщо ваша ОС ігнорує встановлений біт у сценаріях. Це пояснюється тим, що perl поставляється із встановленим кореневим помічником, який виконує необхідні перевірки та повторно закликає інтерпретатора на потрібні сценарії з бажаними привілеями. Це пояснено в посібнику з perlsec . Раніше було встановлено, що #!/usr/bin/suidperl -wT
замість них потрібні встановлені сценарії Perl #!/usr/bin/perl -wT
, але в більшості сучасних систем #!/usr/bin/perl -wT
.
Зауважте, що використання вбудованої бінарної обгортки нічого не означає, щоб запобігти цим проблемам . Насправді, це може зробити ситуацію ще гірше , тому що це може запобігти середовища виконання від виявлення того, що вона викликається з правами і в обхід його виконання налаштування.
Народний двійковий оболонку може зробити сценарій оболонки безпечним, якщо обгортка захищає навколишнє середовище . Сценарій повинен дбати про те, щоб не робити занадто багато припущень (наприклад, про поточний каталог), але це стосується. Ви можете використовувати судо для цього за умови, що він налаштований на оздоровлення навколишнього середовища. Змінні в чорному списку сприйнятливі до помилок, тому завжди дозволені. З Судо, переконайтеся , що env_reset
опція включена, то setenv
вимкнений, і що env_file
і env_keep
містять тільки нешкідливі змінні.
TL, DR:
- Сетуїд Шебанг небезпечний, але зазвичай ігнорується.
- Якщо ви запускаєте програму з привілеями (через sudo або setuid), напишіть нативний код або perl або запустіть програму обгорткою, яка дезінфікує середовище (наприклад, sudo з
env_reset
опцією).
¹ Ця дискусія застосовується однаково, якщо ви заміните "setgid" на "setuid"; вони ігноруються ядром Linux у скриптах