GNU/Linux >> Linux Esercitazione >  >> Linux

Usare correttamente il bit Setuid?

Ho un processo che richiede i privilegi di root quando viene eseguito da un utente normale. Apparentemente posso usare il "bit setuid" per raggiungere questo obiettivo. Qual è il modo corretto di farlo su un sistema POSIX?

Inoltre, come posso farlo con uno script che utilizza un interprete (bash, perl, python, php, ecc.)?

Risposta accettata:

Il bit setuid può essere impostato su un file eseguibile in modo che una volta eseguito, il programma avrà i privilegi del proprietario del file invece che dell'utente reale, se diversi. Questa è la differenza tra efficace uid (id utente) e reale uid.

Alcune utilità comuni, come passwd , sono di proprietà di root e configurati in questo modo per necessità (passwd deve accedere a /etc/shadow che può essere letto solo da root).

La strategia migliore quando si esegue questa operazione è fare immediatamente tutto ciò che è necessario fare come superutente, quindi ridurre i privilegi in modo che sia meno probabile che si verifichino bug o usi impropri durante l'esecuzione di root. Per fare ciò, imposti il ​​processo efficace uid al suo vero uid. In POSIX C:

#define _POSIX_C_SOURCE 200112L // Needed with glibc (e.g., linux).
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

void report (uid_t real) {
    printf (
        "Real UID: %d Effective UID: %dn",
        real,
        geteuid()
    );
}

int main (void) {
    uid_t real = getuid();
    report(real);
    seteuid(real);
    report(real);
    return 0;
}

Le funzioni rilevanti, che dovrebbero avere un equivalente nella maggior parte delle lingue di livello superiore se vengono utilizzate comunemente sui sistemi POSIX:

  • getuid() :Ottieni il vero uid.
  • geteuid() :Ottieni il efficace uid.
  • seteuid() :imposta l'efficace uid.

Non puoi fare nulla con l'ultimo inappropriato per l'uid reale tranne se il bit setuid è stato impostato sull'eseguibile . Quindi, per provare questo, compila gcc test.c -o testuid . È quindi necessario, con privilegi:

chown root testuid
chmod u+s testuid

L'ultimo imposta il bit setuid. Se ora esegui ./testuid come utente normale vedrai che il processo viene eseguito per impostazione predefinita con uid effettivo 0, root.

E gli script?

Questo varia da piattaforma a piattaforma, ma su Linux, le cose che richiedono un interprete, incluso il bytecode, non possono utilizzare il bit setuid a meno che non sia impostato sull'interprete (il che sarebbe molto molto stupido). Ecco un semplice script perl che imita il codice C sopra:

#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);

print "Real UID: $< Effective UID: $>n";
$> = $<; # Not an ASCII art greedy face, but genuine perl...
print "Real UID: $< Effective UID: $>n"; 

Fedele alle sue *nixy radici, perl ha costruito variabili speciali per un uid efficace ($> ) e uid reale ($< ). Ma se provi lo stesso chown e chmod usato con l'eseguibile compilato (da C, esempio precedente), non farà alcuna differenza. Lo script non può ottenere privilegi.

Correlati:come aggiornare correttamente bash a v4.0+?

La risposta è usare un binario setuid per eseguire lo script:

#include <stdio.h>
#include <unistd.h> 

int main (int argc, char *argv[]) {
    if (argc < 2) {
        puts("Path to perl script required.");
        return 1;
    }
    const char *perl = "perl";
    argv[0] = (char*)perl;
    return execv("/usr/bin/perl", argv);
}

Compila questo gcc --std=c99 whatever.c -o perlsuid , quindi chown root perlsuid && chmod u+s perlsuid . Ora puoi eseguire qualsiasi perl con un uid effettivo pari a 0, indipendentemente da chi lo possiede.

Una strategia simile funzionerà con php, python, ecc. Ma...

# Think hard, very important:
>_< # Genuine ASCII art "Oh tish!" face

PER FAVORE PER FAVORE NON lasciare questo genere di cose in giro . Molto probabilmente, vuoi effettivamente compilare il nome dello script come un percorso assoluto , ovvero sostituisci tutto il codice in main() con:

    const char *args[] = { "perl", "/opt/suid_scripts/whatever.pl" }
    return execv("/usr/bin/perl", (char * const*)args);

Si assicurano /opt/suid_scripts e tutto ciò che contiene è di sola lettura per utenti non root. Altrimenti, qualcuno potrebbe scambiare qualsiasi cosa con whatever.pl .

Inoltre, fai attenzione che molti linguaggi di scripting consentono alle variabili di ambiente di cambiare il modo in cui eseguono uno script . Ad esempio, una variabile di ambiente potrebbe causare il caricamento di una libreria fornita dal chiamante, consentendo al chiamante di eseguire codice arbitrario come root. Pertanto, a meno che tu non sappia che sia l'interprete che lo script stesso sono robusti rispetto a tutte le possibili variabili di ambiente, NON FARLO .

Quindi cosa dovrei fare invece?

Un modo più sicuro per consentire a un utente non root di eseguire uno script come root è aggiungere una regola sudo e fare in modo che l'utente esegua sudo /path/to/script . Sudo elimina la maggior parte delle variabili di ambiente e consente inoltre all'amministratore di selezionare con precisione chi può eseguire il comando e con quali argomenti. Vedi Come eseguire un programma specifico come root senza una richiesta di password? per un esempio.


Linux
  1. Usando –exclude con il comando Du?

  2. Utilizzo dell'interfaccia universale di scacchi

  3. kdevtmpfsi usando l'intera CPU

  4. SELinux nel mondo reale

  5. Qual è l'overhead dell'utilizzo di subshell?

Suggerimenti per l'utilizzo del comando top in Linux

Usando il comando gratuito di Linux

Utilizzo del file di configurazione SSH

Tutorial sull'uso del comando Timeout su Linux

Tutorial sull'utilizzo dell'ultimo comando nel terminale Linux

Perché il bit setuid funziona in modo incoerente?