GNU/Linux >> Znalost Linux >  >> Linux

Proč je SUID zakázáno pro skripty prostředí, ale ne pro binární soubory?

Způsobu shebang je vlastní rasa (#! ) se obvykle implementuje:

  1. Jádro otevře spustitelný soubor a zjistí, že začíná #! .
  2. Jádro zavře spustitelný soubor a místo toho otevře interpret.
  3. 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 interpret dostane k otevírá svůj první argument. Z tohoto důvodu všechny moderní unice ignorují 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 udělaly správnou funkci zámku obzvláště obtížnou a invazivní. Nemyslím si, že to někdo dělá tímto způsobem.

Několik unixových systémů implementuje bezpečný setuid shebang pomocí další funkce:cesta /dev/fd/N odkazuje na soubor již otevřený na deskriptoru souboru N (takže otevření /dev/fd/N je zhruba ekvivalentní dup(N) ).

  1. Jádro otevře spustitelný soubor a zjistí, že začíná #! . Řekněme, že deskriptor souboru pro spustitelný soubor je 3.
  2. Jádro otevře interpret.
  3. Jádro vloží /dev/fd/3 seznam argumentů (jako argv[1] ) a spustí interpret.

Všechny moderní unixové varianty včetně Linuxu implementují /dev/fd , ale většina nepovoluje skripty setuid. OpenBSD, NetBSD a Mac OS X jej podporují, pokud povolíte jiné než výchozí nastavení jádra. V Linuxu lidé napsali záplaty, které to umožňují, ale tyto záplaty nebyly nikdy začleněny. Stránka shebang Svena Maschecka obsahuje spoustu informací o shebangu napříč uniicemi, včetně podpory setuid.

Kromě toho programy běžící se zvýšenými oprávněními mají vlastní rizika, která je obvykle obtížnější ovládat v programovacích jazycích vyšší úrovně, pokud pro to nebyl interpreter speciálně navržen. Důvodem je, že inicializační kód modulu runtime programovacího jazyka může provádět akce se zvýšenými oprávněními na základě dat, která jsou zděděna od volajícího s nižším oprávněním, dříve než vlastní kód programu dostane příležitost tato data dezinfikovat. Runtime C dělá pro programátora velmi málo, takže programy C mají lepší příležitost převzít kontrolu a dezinfikovat data dříve, než se stane něco špatného.

Předpokládejme, že se vám podařilo spustit 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 se váš runtime systém chová bezpečně, pokud je spuštěn s oprávněními.

  • Každý 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 běž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ého libc.so v $LD_LIBRARY_PATH (mimo jiné taktiky). Všechny rozumné systémy ignorují LD_* proměnné ve spustitelných souborech setuid.

  • V shellech, jako je sh, csh a deriváty, se proměnné prostředí 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 nastavují 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ích, bajtkódových nebo interpretovaných) má podobné funkce. Málokdo přijímá zvláštní opatření ve spustitelných souborech 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 setuid perl skripty 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 obálky 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 zabránit vašemu běhovému prostředí v tom, aby zjistilo, že je voláno s oprávněními, a obešlo jeho konfigurovatelnost běhového prostředí.

Nativní binární obal může zajistit, aby byl skript shellu bezpečný, pokud obal vyčistí prostředí. Skript si musí dát pozor, aby nevytvářel příliš mnoho předpokladů (např. o aktuálním adresáři), ale to jde. 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 zapnutá, že setenv je vypnutý a env_file a env_keep obsahovat pouze neškodné proměnné.

Všechny tyto úvahy platí stejně pro jakékoli zvýšení oprávnění:setuid, setgid, setcap.

Recyklováno z https://unix.stackexchange.com/questions/364/allow-setuid-on-shell-scripts/2910#2910


Především proto

Mnoho jader trpí sporem, který vám umožňuje vyměnit skript shellu za jiný spustitelný soubor podle vašeho výběru mezi dobou, kdy nově exec()ed proces přejde do nastavení, a když se spustí interpret příkazů. Pokud jste dostatečně vytrvalí, teoreticky byste mohli přimět jádro, aby spustilo jakýkoli program, který chcete.

stejně jako další důvody nalezené na tomto odkazu (ale nejzhoubnější je rasová podmínka jádra). Skripty se samozřejmě načítají jinak než binární programy, což je místo, kde se chyba vkrádá.

Možná vás pobaví, když si přečtete tento článek Dr. Dobba z roku 2001 – který prochází 6 kroky k psaní bezpečnějších skriptů shellu SUID, až se dostanete ke kroku 7:

Lekce sedm – Nepoužívejte skripty shellu SUID.

I po vší naší práci je téměř nemožné vytvořit bezpečné skripty SUIDshell. (Na většině systémů je to nemožné.) Kvůli těmto problémům některé systémy (např. Linux) nebudou respektovat SUID na shellscriptech.

Tato historie hovoří o tom, které varianty měly opravy pro podmínku závodu; seznam je větší, než byste si mysleli... ale skripty setuid jsou stále z velké části odrazovány kvůli jiným problémům nebo proto, že je snazší je odradit, než si pamatovat, zda používáte bezpečnou nebo nebezpečnou variantu.

To byl tehdy dost velký problém, že je poučné číst o tom, jak agresivně Perl přistupoval ke kompenzaci.


Linux
  1. Proč nepoužít „který“? Co tedy použít?

  2. Povolit skripty Setuid On Shell?

  3. Rozšíření souborů pro skripty Unix Shell?

  1. Linux – Proč Setuid nefunguje?

  2. Linux – Proč Locale Es_mx funguje, ale Es ne?

  3. Proč dokument Parent Shell Here nefunguje pro dílčí příkaz v Dash, ale funguje Bash?

  1. Proč „ls“ vyžaduje samostatný proces pro provedení?

  2. Unit testování pro shell skripty

  3. Proč nevidím MSG_EOR pro SOCK_SEQPACKET na linuxu?