Anii `setuid permisiunea bit spune Linux pentru a rula un program cu efective id-ul de utilizator al proprietarului, în loc de executorul:
> 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
Cu toate acestea, aceasta se aplică numai pentru executabile; shell script-uri ignora setuid pic:
> cat setuid-test2
#!/bin/bash
id -u
> ./setuid-test2
1000
> sudo chown nobody ./setuid-test2; sudo chmod +s ./setuid-test2
> ./setuid-test2
1000
Wikipedia spune:
Datorita risc crescut de defecte de securitate, mai multe sisteme de operare ignora setuid atribut atunci când este aplicat la executabil script-uri shell.
Presupunând că am'm dispuși să accepte aceste riscuri, nu există nici o modalitate de a spune Linux pentru a trata setuid cam la fel pe shell script-uri ca pe executabile?
Dacă nu, există o comună soluție pentru această problemă? Soluția mea actuală este de a adăuga o sudoers intrare pentru a permite "TOATE" pentru a rula un script ca utilizatorul eu vreau ca, cu NOPASSWD
pentru a evita prompt parolă. Principalele dezavantaje este nevoie de o sudoers
de intrare de fiecare dată când vreau să fac acest lucru, și aveți nevoie pentru a apelantului la sudo unele-script
în loc de unele-script
#!
line). De comp.unix.întrebări FAQ explică problemele de securitate cu setuid script-uri shell. Aceste probleme sunt de două tipuri: tacâmul legate și shell-legate; intru în mai multe detalii mai jos.
Dacă tu nu't pasă de securitate și doriți să permiteți setuid scripturi, sub Linux, ai'll nevoie pentru a patch-uri de kernel. Ca de 3.x kernel, cred că aveți nevoie să adăugați un apel la install_exec_creds
în load_script
funcția, înainte de apelul la open_exec
, dar nu am't testat. Există o cursă condiție inerentă pentru modul tacâmul (#!
) este de obicei pus în aplicare:
#!
. argv[1]
), și execută interpret.
Dacă setuid script-uri sunt permise cu această punere în aplicare, un atacator poate invoca un arbitrar script prin a crea o legătură simbolică la un existent setuid script, executarea, și aranjarea de a schimba link-ul de după kernel-a efectuat pasul 1 și înainte de interpret devine în jurul valorii de la deschiderea primului argument. Pentru acest motiv, cel mai unices ignora setuid pic atunci când detectează o afacere.
O modalitate de a asigura această aplicare ar fi pentru kernel-ul pentru a bloca fișierul script până interpretul a deschis-o (rețineți că acest lucru trebuie să împiedice nu numai deconectarea sau suprascrierea fișierului, dar, de asemenea, redenumirea orice director în cale). Dar sistemele unix tind să timid departe de obligatorie încuietori, și link-uri simbolice ar face o corecta caracteristica de blocare deosebit de dificil și invazive. Eu nu't cred că nimeni nu-l în acest fel.
Câteva sisteme unix (în principal, OpenBSD, NetBSD și Mac OS X, toate care necesită un nucleu setare să fie activat) să pună în aplicare secure setuid tacâmul folosind o caracteristică suplimentară: calea /dev/fd
dar nu setuid script-uri. #!
. Las's spun descriptorul de fișier pentru executabil este de 3. /dev/fd/3
lista de argumente (ca argv[1]
), și execută interpret.
Sven Mascheck's tacâmul pagina are o mulțime de informații pe tacâmul peste unices, inclusiv setuid suport. Las's presupunem tine'am reusit sa fac programul rula ca root, fie pentru că sistemul de OPERARE suportă setuid treaba sau pentru ca'am folosit un binar nativ înveliș (cum ar fi "sudo"). Ai deschis o gaură de securitate? Poate. Problema aici este nu despre interpretat vs elaborate programe. Problema este dacă runtime system se comportă în condiții de siguranță dacă este executată cu privilegii.
/lib/ld.deci
), care încarcă biblioteci dinamice cerute de program. Pe multe unices, puteți configura calea de căutare pentru biblioteci dinamice prin mediu (LD_LIBRARY_PATHeste un nume comun pentru variabila de mediu), și chiar încărca biblioteci suplimentare în toate executat binare (
LD_PRELOAD). La invoker din programul poate executa cod arbitrar, în care programul de's context, prin plasarea unui special conceput
libc.atât de " în " $LD_LIBRARY_PATH(printre alte tactici). Toate sănătoasă sisteme ignora
LD*` variabile în setuid executabile. #!/usr/bin/suidperl -wT "în loc de"#! /usr/bin/perl-wT
, dar pe cele mai multe sisteme moderne, #!/usr/bin/perl-wT
este suficient.
Rețineți că, folosind un binar nativ wrapper nu face nimic în sine, pentru a preveni aceste probleme. În fapt, se poate face situația rău, pentru că s-ar putea preveni runtime environment de la detectarea că este invocat cu privilegii și ocolind sale de execuție configurabilitate.
Un binar nativ wrapper poate face un script de shell în siguranță dacă ambalajul igienizează mediu. Script-ul trebuie să aibă grijă să nu facă prea multe ipoteze (de exemplu, despre directorul curent), dar merge. Puteți folosi sudo pentru acest lucru, cu condiția ca acesta's înființat pentru igienizarea mediului. Pe lista neagră variabile este predispusă la erori, astfel încât întotdeauna albă. Cu sudo, asigurați-vă că env_reset
opțiune este activată, că setenv
este oprit, și că env_file " și " env_keep
conține numai inofensive variabile. TL,DR:
env_reset
opțiune).
¹ Această discuție se aplică în mod egal dacă ai înlocui "setgid" pentru "setuid"; ambele sunt ignorate de către kernel-ul Linux pe scripturi O modalitate de a rezolva această problemă este de a apela shell script-ul de la un program care poate folosi setuid pic. ceva cum ar fi sudo. De exemplu, aici este modul în care ar realiza acest lucru într-un program C:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
setuid( 0 ); // you can set it at run time also
system( "/home/pubuntu/setuid-test2.sh" );
return 0;
}
Salvați-l ca suid-test2.c. compila Acum face suid pe acest program binar:
su - nobody
[enter password]
chown nobody:nobody a.out
chmod 4755 a.out
Acum, ar trebui să fie capabil să-l rulați, și te'll vedea script-ul a fost executat cu nimeni permisiuni. Dar aici, de asemenea, fie aveți nevoie pentru a hardcode script drumul sau trece-l ca linie de comandă arg de mai sus exe.
Am prefix câteva script-uri care sunt în această barcă astfel:
#!/bin/sh
[ "root" != "$USER" ] && exec sudo $0 "$@"
Rețineți că acest lucru nu folosesc setuid` ci pur și simplu execută fișierul curent cu "sudo".
Dacă doriți, pentru a evita apelarea sudo some_script
puteți face:
#!/ust/bin/env sh
sudo /usr/local/scripts/your_script
SETUID programe trebuie să fie proiectat cu o deosebită grijă ca ei rula cu privilegii de root, iar utilizatorii au control mare asupra lor. Ei au nevoie de bun-simț verifica totul. Nu se poate face cu script-uri, deoarece:
sed
, awk
, etc. ar trebui să fie verificate, precum șiVă rugăm să rețineți că "sudo" oferă un bun-simț-verificare dar e't suficient — verifica fiecare linie în propriul cod.
Ca o ultimă notă: luați în considerare utilizarea capacităților. Acestea vă permit să dea un proces care rulează ca un utilizator privilegii speciale care în mod normal ar avea nevoie de privilegii de root. Cu toate acestea, de exemplu, în timp ce "ping" trebuie să manipuleze rețea, aceasta nu trebuie să aibă acces la fișiere. Am'm nu sunt sigur cu toate acestea, dacă acestea sunt moștenite.
Puteți crea un alias pentru sudo + numele de script-ul. Desigur, că este chiar mai mult de lucru pentru a configura, deoarece atunci aveți pentru a configura un alias, de asemenea, dar vă salvează de la a fi nevoie să introduceți sudo.
Dar dacă nu't mintea oribil riscuri de securitate, utilizați un setuid shell ca interpret pentru shell script. Don't știu dacă asta'll de lucru pentru tine, dar cred că s-ar putea.
Permiteți-mi să declar că am sfătui împotriva fapt, a face acest lucru, deși. Am'm a menționat doar pentru scopuri educaționale ;-)
super [ -r reqpath] comanda [ argumente ]
Super vă permite specificate de utilizatori pentru a executa script-uri (sau alte comenzi), ca daca au rădăcină; sau se poate seta uid, gid, și/sau suplimentare grupuri pe baza de comanda înainte de a executa comanda. Acesta este destinat a fi o alternativă sigură, pentru a face script-uri setuid root. Super, de asemenea, permite utilizatorilor obișnuiți să furnizeze comenzi pentru executarea de către alții; aceste executa cu uid, gid, și grupuri de utilizator, oferind comanda.
Super consultă un `super.tab'' de fișier pentru a vedea dacă utilizatorul este permis să execute comanda solicitată. Dacă permisiunea este acordată, super va exec pgm [ args ], unde pgm este un program care este asociat cu această comandă. (Root este permisă executarea în mod implicit, dar poate fi refuzat în cazul în care o regulă exclude rădăcină. Utilizatorii obișnuiți sunt nepermis de execuție în mod implicit.)
Dacă comanda este o legătură simbolică (sau hard-link-ul, de asemenea) la super program, apoi tastați % comanda args este echivalent cu tastarea % super comanda args (comanda nu trebuie să fie super sau super nu va recunoaște că l's fi invocată prin intermediul unui link.)
http://www.ucolick.org/~va/RUE/super/README
http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html
Dacă pentru un motiv oarecare "sudo" nu este disponibil, puteți scrie un înveliș subțire script-ul in C:
#include <unistd.h>
int main() {
setuid(0);
execle("/bin/bash","bash","/full/path/to/script",(char*) NULL,(char*) NULL);
}
Și odată ce-l compilați-l setați ca setuid " cu " chmod 4511 wrapper_script
.
Acest lucru este similar cu un alt răspuns postat, dar ruleaza script-ul cu un mediu curat și folosește explicit /bin/bash
în loc de coajă numit de sistem()`, și astfel se închide un potențial de gauri de securitate.
Rețineți că această capturilor aruncate înapoi în mare mediu în întregime. Dacă doriți să utilizați unele variabile de mediu, fără a deschide vulnerabilități, chiar ai nevoie doar de a folosi "sudo".
Evident, vrei să asigurați-vă că script-ul în sine este numai scris de rădăcină.
Am găsit pentru prima dată această întrebare, convins de toate răspunsurile, aici este una mult mai buna, care, de asemenea, vă permite să complet obfuscate ta script bash, dacă sunteți atât de înclinat!
Ar trebui să fie auto-explicative.
#include <string>
#include <unistd.h>
template <typename T, typename U>
T &replace (
T &str,
const U &from,
const U &to)
{
size_t pos;
size_t offset = 0;
const size_t increment = to.size();
while ((pos = str.find(from, offset)) != T::npos)
{
str.replace(pos, from.size(), to);
offset = pos + increment;
}
return str;
}
int main(int argc, char* argv[])
{
// Set UUID to root
setuid(0);
std::string script =
R"(#!/bin/bash
whoami
echo $1
)";
// Escape single quotes.
replace(script, std::string("'"), std::string("'\"'\"'"));
std::string command;
command = command + "bash -c '" + script + "'";
// Append the command line arguments.
for (int a = 0; a < argc; ++a)
{
command = command + " " + argv[a];
}
return system(command.c_str());
}
Apoi fugi
g++ embedded.cpp -o embedded
sudo chown root embedded
sudo chmod u+s embedded