GNU/Linux >> Znalost Linux >  >> Linux

Povolit skripty Setuid On Shell?

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:

  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 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.

  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.
Související:Jaké jsou speciální parametry/proměnné (Bash) shellu?

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é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 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é.

Související:Jak uniknout uvozovkám v shellu?

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


Linux
  1. Asociativní pole ve skriptech Shell?

  2. Jak zrušit kořenová oprávnění ve skriptech Shell?

  3. Skrýváte heslo ve skriptech Shell?

  1. Sdílení proměnných ve více skriptech Shell?

  2. Jak otestovat shodu skriptů Shell s Posix?

  3. Rozdělení dlouhých příkazů ve skriptech Shell?

  1. Správné zamykání skriptů Shell?

  2. Spouštět skripty Shell přes web?

  3. Jak spouštět skripty Pythonu ze shellu