2011-12-14 12 views
32

Questo è un programma di set-root-uidRealUID, UID salvato, UID efficace. Cosa sta succedendo?

$ls -l 
-rwsr-sr-x 1 root root 7406 2011-12-13 22:37 ./x* 

Il codice sorgente:

int main(void) { 
    printf(
     "   UID   GID \n" 
     "Real  %d Real  %d \n" 
     "Effective %d Effective %d \n", 
      getuid(),  getgid(), 
      geteuid(),  getegid() 
    ); 

seteuid(600); 
    printf(
     "   UID   GID \n" 
     "Real  %d Real  %d \n" 
     "Effective %d Effective %d \n", 
      getuid(),  getgid(), 
      geteuid(),  getegid() 
    ); 

setuid(1000); 

    printf(
     "   UID   GID \n" 
     "Real  %d Real  %d \n" 
     "Effective %d Effective %d \n", 
      getuid(),  getgid(), 
      geteuid(),  getegid() 
    ); 

setuid(0); // HOW DOES THIS SUCCEED IN SETTING THE EUID BACK TO 0 
    printf(
     "   UID   GID \n" 
     "Real  %d Real  %d \n" 
     "Effective %d Effective %d \n", 
      getuid(),  getgid(), 
      geteuid(),  getegid() 
    ); 

    return 0 ;  
} 

USCITA

  UID   GID 
Real  1000 Real  1000 
Effective 0 Effective 0 
     UID   GID 
Real  1000 Real  1000 
Effective 600 Effective 0 
     UID   GID 
Real  1000 Real  1000 
Effective 1000 Effective 1000 
     UID   GID 
Real  1000 Real  1000 
Effective 0 Effective 1000 

La mia domanda

La pagina man membri che setuid cambia l'uid reale, salvato ed efficace. Quindi dopo la chiamata setuid(1000), tutti e tre cambiano in 1000. Come è che setuid(0) mi consente di cambiare euid a 0?

risposta

24

Ci sono due casi,

  1. si vuole far cadere temporaneamente i privilegi di root durante l'esecuzione di setuid programma
  2. Si desidera eliminare definitivamente il privilegio di root durante l'esecuzione del programma setuid ...
  • Puoi farlo temporaneamente impostando l'euid al reale user id e quindi modificando l'uid a nulla want.and più tardi, quando è necessario il privilegio di root retro è possibile setuid a root e l'ID utente effettivo cambierà torna alla radice. Questo perché l'ID utente salvato non è cambiato.
  • È possibile rilasciare il privilegio in modo permanente cambiando l'UID immediatamente con un ID utente con privilegi minori. Dopo questo, non importa cosa non si possa riavere il privilegio di root.

Caso 1:

Dopo un programma setuid inizia l'esecuzione

1.seteuid(600); 
2.setuid(1000); 
3.setuid(0); 

Per questo caso i privilegi di root può essere acquisita di nuovo.

   +----+------+------------+ 
       | uid|euid |saved-uid | 
       |----|------|------------| 
      1.|1000| 0 | 0   | 
      2.|1000| 600 | 0   | 
      3.|1000| 1000 | 0   | 
      4.|1000| 0 | 0   | 
       | |  |   | 
       +------------------------+ 

Caso 2:

Dopo un programma setuid inizia l'esecuzione,

1.setuid(1000); 
2.setuid(0); 



       +----+------+------------+ 
       | uid|euid |saved-uid | 
       |----|------|------------| 
      1.|1000|0  | 0   | 
      2.|1000|1000 | 1000  | 
       | |  |   | 
       +------------------------+ 

In questo caso non è possibile ottenere indietro il privilegi di root. Questo può essere verificato con il seguente comando,

cat/proc/PROCID/task/PROCID/status | meno

Uid: 1000 0  0  0 
Gid: 1000 0  0  0 

Questo comando visualizzerà un UID e GID e avrà 4 campi (i primi tre campi sono quello che ci interessa). Qualcosa di simile a quanto sopra

I tre campi rappresentano uid, euid e user-id salvato. È possibile introdurre una pausa (un input dall'utente) nel programma setuid e verificare per ogni passaggio il comando cat /proc/PROCID/task/PROCID/status | less. Durante ogni fase è possibile controllare se l'UID salvato viene modificato come indicato.

Se sei euid è root e modificare l'uid, i privilegi viene scartato permanently.If efficace id utente non è root quindi salvato id utente non viene mai toccato e si può ritrovare il privilegio di root di nuovo ogni volta che vuoi nel tuo programma.

+0

Puoi dirmi quale è l'ultima colonna in Uid: 1000 0 0 0 rappresenta –

+0

Quando ho provato a testarlo con un codice di esempio, il quarto valore visualizzato è lo stesso di ID utente effettivo. Indovina che deve essere l'id utente effettivo, ma non è sicuro del motivo per cui dovrebbe stampare due volte l'ID utente effettivo. – Ajai

+1

L'ultima colonna è il FSUID – user368507

8

DESCRIZIONE setuid() imposta l'ID utente effettivo del processo chiamante. Se l'UID effettivo del chiamante è root, vengono impostati anche l'UID reale e l'ID utente set salvato.

Sotto Linux, setuid() è implementato come la versione POSIX con la funzione _POSIX_SAVED_IDS. Questo consente a un programma set-user-ID (diverso da root) di eliminare tutti i suoi privilegi utente, eseguire operazioni non privilegiate e quindi reinserire l'ID utente effettivo originale in modo sicuro.

Se l'utente è root o il programma è impostato-user-ID-root, è necessario prestare particolare attenzione. La funzione setuid() controlla l'ID utente effettivo del chiamante e se è il superutente, tutti gli ID utente relativi al processo sono impostati su uid. Dopo che questo si è verificato, è impossibile per il programma recuperare i privilegi di root.

Pertanto, un programma set-user-ID-root che desidera eliminare temporaneamente i privilegi di root, assumere l'identità di un utente senza privilegi e quindi riottenere i privilegi di root in seguito non può utilizzare setuid(). È possibile eseguire con seteuid (2).

(da Manuale dei programmatori di Linux, 2014/09/21, pag setuid.2)

+0

In base a ciò che hai detto, l'ultimo segmento di output dovrebbe mostrare 'Effective' =' 1000'. Ma è in grado di tornare a '0'. Questa è esattamente la mia domanda. –

+0

Credo che sia dovuto alla chiamata a 'seteuid' che stai facendo; fa sì che il kernel "protegga" la tua capacità di riguadagnare 'root' in futuro. La rimozione di quella chiamata elimina l'effetto "backdoor". – BRFennPocock

+0

Sì, anche la risposta di @ajai fornisce la prova. Grazie comunque per la risposta –

2

O! Queste funzioni sono difficili da utilizzare correttamente.

La pagina man afferma che setuid cambierà l'uid reale, salvato ed effettivo. Così, dopo il chiamando setuid (1000), tutti e tre cambiamento 1000.

Questo è il caso se e solo se si è euid 0. Al momento si chiama setuid(0), tuttavia, siete euid 1000 e salvati uid 0 (controllare getresuid(2), ad esempio). Ecco perché sei in grado di riconquistare i privilegi.

+0

Sei corretto. Il getresuid() sembra funzionare correttamente. Ma non è conforme a 'POSIX'. Ma non importa in questo caso. Grazie.. –

Problemi correlati