setuid
bit oprávnění říká Linuxu, aby spustil program s efektivním uživatelským jménem vlastníka namísto exekutora:
> 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
To se však týká pouze spustitelných souborů; skripty shellu ignorují bit setuid:
> cat setuid-test2
#!/bin/bash
id -u
> ./setuid-test2
1000
> sudo chown nobody ./setuid-test2; sudo chmod +s ./setuid-test2
> ./setuid-test2
1000
Wikipedie říká:
Kvůli zvýšené pravděpodobnosti bezpečnostních chyb mnoho operačních systémů ignoruje atribut setuid při použití na spustitelné skripty shellu.
Za předpokladu, že jsem ochoten přijmout tato rizika, existuje nějaký způsob, jak říct Linuxu, aby s bitem setuid zacházel ve skriptech shellu stejně jako ve spustitelných souborech?
Pokud ne, existuje společné řešení tohoto problému? Moje aktuální řešení je přidat sudoers
záznam povolte ALL
ke spuštění daného skriptu jako uživatele, pod kterým ho chci spustit, pomocí NOPASSWD
abyste se vyhnuli výzvě k zadání hesla. Hlavní nevýhodou je potřeba sudoers
vstup pokaždé, když to chci udělat, a potřeba, aby volající sudo some-script
namísto pouhého some-script
Přijatá odpověď:
Linux ignoruje bit setuid¹ u všech interpretovaných spustitelných souborů (tj. spustitelných souborů začínajících znakem #!
čára). Comp.unix.questions FAQ vysvětluje bezpečnostní problémy se skripty setuid shell. Tyto problémy jsou dvojího druhu:související se shebangem a související se shellem; Více podrobností zacházím níže.
Pokud se nestaráte o zabezpečení a chcete povolit skripty setuid, pod Linuxem budete muset opravit jádro. Od jader 3.x si myslím, že musíte přidat volání install_exec_creds
v load_script
funkce, před voláním open_exec
, ale netestoval jsem.
Setuid shebang
Způsobu shebang je vlastní rasa (#!
) se obvykle implementuje:
- Jádro otevře spustitelný soubor a zjistí, že začíná
#!
. - Jádro zavře spustitelný soubor a místo toho otevře interpret.
- Jádro vloží cestu ke skriptu do seznamu argumentů (jako
argv[1]
) a spustí interpret.
Pokud jsou s touto implementací povoleny skripty setuid, útočník může vyvolat libovolný skript vytvořením symbolického odkazu na existující skript setuid, jeho spuštěním a uspořádáním změny odkazu poté, co jádro provede krok 1 a než se k němu dostane interpret. otevírá svůj první argument. Z tohoto důvodu většina unices ignoruje setuid bit když detekují shebang.
Jedním ze způsobů zabezpečení této implementace by bylo, kdyby jádro uzamklo soubor skriptu, dokud jej interpret neotevře (všimněte si, že to musí zabránit nejen odpojení nebo přepsání souboru, ale také přejmenování libovolného adresáře v cestě). Ale unixové systémy mají tendenci vyhýbat se povinným zámkům a symbolické odkazy by způsobily, že funkce správného zámku je obzvláště obtížná a invazivní. Nemyslím si, že to někdo dělá tímto způsobem.
Několik unixových systémů (hlavně OpenBSD, NetBSD a Mac OS X, z nichž všechny vyžadují povolení nastavení jádra) implementuje secure setuid shebang pomocí další funkce:cesta /dev/fd/N
odkazuje na soubor již otevřený na deskriptoru souboru N (takže otevřete /dev/fd/N
je zhruba ekvivalentní dup(N)
). Mnoho unixových systémů (včetně Linuxu) má /dev/fd
ale ne setuid skripty.
- Jádro otevře spustitelný soubor a zjistí, že začíná
#!
. Řekněme, že deskriptor souboru pro spustitelný soubor je 3. - Jádro otevře interpret.
- Jádro vloží
/dev/fd/3
seznam argumentů (jakoargv[1]
) a spustí interpret.
Stránka Shebang Svena Maschecka má spoustu informací o shebang napříč unices, včetně podpory setuid.
Překladače Setuid
Předpokládejme, že se vám podařilo spustit váš program jako root, buď proto, že váš operační systém podporuje setuid shebang, nebo protože jste použili nativní binární obal (například sudo
). Otevřeli jste bezpečnostní díru? Možná . Problém zde není o interpretovaných vs kompilovaných programech. Otázkou je, zda váš běhový systém chová se bezpečně, pokud je spuštěn s oprávněními.
-
Jakýkoli dynamicky propojený nativní binární spustitelný soubor je způsobem interpretován dynamickým zavaděčem (např.
/lib/ld.so
), který načte dynamické knihovny požadované programem. Na mnoha unicích můžete nakonfigurovat cestu vyhledávání pro dynamické knihovny prostřednictvím prostředí (LD_LIBRARY_PATH
je společný název pro proměnnou prostředí) a dokonce načte další knihovny do všech spuštěných binárních souborů (LD_PRELOAD
). Vyvolávač programu může spustit libovolný kód v kontextu tohoto programu umístěním speciálně vytvořenéholibc.so
v$LD_LIBRARY_PATH
(mimo jiné taktiky). Všechny rozumné systémy ignorujíLD_*
proměnné ve spustitelných souborech setuid. -
V mušle jako jsou sh, csh a deriváty, proměnné prostředí se automaticky stávají parametry shellu. Prostřednictvím parametrů, jako je
PATH
,IFS
a mnoho dalších, vyvolávač skriptu má mnoho příležitostí ke spuštění libovolného kódu v kontextu skriptů shellu. Některé shelly nastaví tyto proměnné na rozumné výchozí hodnoty, pokud zjistí, že skript byl vyvolán s oprávněními, ale nevím, že by existovala nějaká konkrétní implementace, které bych věřil. -
Většina běhových prostředí (ať už nativní, bytecode nebo interpretované) mají podobné vlastnosti. Málokdo přijímá zvláštní opatření u spustitelných souborů setuid, i když ty, které spouštějí nativní kód, často nedělají nic lepšího než dynamické spojování (které vyžaduje opatření).
-
Perl je výraznou výjimkou. Explicitně podporuje skripty setuid bezpečným způsobem. Ve skutečnosti může váš skript spustit setuid, i když váš operační systém ignoroval bit setuid ve skriptech. Je to proto, že perl je dodáván s pomocníkem setuid root, který provádí nezbytné kontroly a znovu vyvolává interpret na požadovaných skriptech s požadovanými právy. To je vysvětleno v příručce perlsec. Bývalo to tak, že skripty setuid perl potřebovaly
#!/usr/bin/suidperl -wT
místo#!/usr/bin/perl -wT
, ale na většině moderních systémů#!/usr/bin/perl -wT
je dostačující.
Všimněte si, že použití nativního binárního wrapperu samo o sobě nevede k zabránění těmto problémům . Ve skutečnosti to může situaci zhoršit , protože to může vašemu běhovému prostředí zabránit v tom, aby zjistilo, že je voláno s oprávněními, a obcházelo jeho konfigurovatelnost běhového prostředí.
Nativní binární obal může zabezpečit skript shellu, pokud obal dezinfikuje prostředí . Skript si musí dát pozor, aby nevytvářel příliš mnoho předpokladů (např. o aktuálním adresáři), ale jde to. K tomu můžete použít sudo za předpokladu, že je nastaveno na dezinfekci prostředí. Blacklistování proměnných je náchylné k chybám, proto vždy seznam povolených. U sudo se ujistěte, že env_reset
je zapnuta tato možnost setenv
je vypnutý a env_file
a env_keep
obsahovat pouze neškodné proměnné.
TL,DR:
- Setuid shebang je nejistý, ale obvykle se ignoruje.
- Pokud spouštíte program s oprávněními (buď prostřednictvím sudo nebo setuid), napište nativní kód nebo perl nebo spusťte program s obalem, který dezinfikuje prostředí (jako je sudo s
env_reset
možnost).
¹ Tato diskuse platí stejně, pokud dosadíte „setgid“ za „setuid“; oba jsou ignorovány linuxovým jádrem ve skriptech