Erlaube „setuid“ in Shell-Skripten

Erlaube „setuid“ in Shell-Skripten

Das setuidBerechtigungsbit weist Linux an, ein Programm mit der effektiven Benutzer-ID des Eigentümers statt des Ausführers auszuführen:

> 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

Dies gilt jedoch nur für ausführbare Dateien; Shell-Skripte ignorieren das Setuid-Bit:

> cat setuid-test2

#!/bin/bash
id -u

> ./setuid-test2

1000

> sudo chown nobody ./setuid-test2; sudo chmod +s ./setuid-test2
> ./setuid-test2

1000

Wikipediasagt:

Aufgrund der erhöhten Wahrscheinlichkeit von Sicherheitslücken ignorieren viele Betriebssysteme das Setuid-Attribut, wenn es auf ausführbare Shell-Skripte angewendet wird.

Vorausgesetzt, ich bin bereit, diese Risiken einzugehen, gibt es eine Möglichkeit, Linux anzuweisen, das Setuid-Bit in Shell-Skripten genauso zu behandeln wie in ausführbaren Dateien?

sudoersWenn nicht, gibt es eine allgemeine Problemumgehung für dieses Problem? Meine aktuelle Lösung besteht darin, einen Eintrag hinzuzufügen, der es ermöglicht ALL, ein bestimmtes Skript als der Benutzer auszuführen, unter dem ich es ausführen möchte, um die Kennwortabfrage zu vermeiden. Die Hauptnachteile dabei sind, dass jedes Mal, wenn ich dies tun möchte, NOPASSWDein Eintrag erforderlich ist und dass der Anrufer nicht nursudoerssudo some-scriptsome-script

Antwort1

Linux ignoriert das setuid¹-Bit bei allen interpretierten ausführbaren Dateien (also bei ausführbaren Dateien, die mit einer #!Zeile beginnen).Häufig gestellte Fragen zu comp.unix.questionserklärt die Sicherheitsprobleme mit Setuid-Shell-Skripten. Es gibt zwei Arten von Problemen: Shebang-bezogene und Shell-bezogene. Ich gehe weiter unten näher darauf ein.

Wenn Sie sich nicht um Sicherheit kümmern und Setuid-Skripte zulassen möchten, müssen Sie unter Linux den Kernel patchen. Ab 3.x-Kerneln müssen Sie, glaube ich, einen Aufruf hinzufügen, uminstall_exec_credsimload_scriptFunktion, vor dem Aufruf von open_exec, aber ich habe es nicht getestet.


Setuid-Kram

#!Bei der typischen Implementierung von shebang() tritt ein gewisser Race Condition auf :

  1. Der Kernel öffnet die ausführbare Datei und stellt fest, dass sie mit beginnt #!.
  2. Der Kernel schließt die ausführbare Datei und öffnet stattdessen den Interpreter.
  3. Der Kernel fügt den Pfad zum Skript in die Argumentliste ein (als argv[1]) und führt den Interpreter aus.

Wenn Setuid-Skripte mit dieser Implementierung erlaubt sind, kann ein Angreifer ein beliebiges Skript aufrufen, indem er einen symbolischen Link zu einem vorhandenen Setuid-Skript erstellt, es ausführt und dafür sorgt, dass der Link geändert wird, nachdem der Kernel Schritt 1 ausgeführt hat und bevor der Interpreter dazu kommt, sein erstes Argument zu öffnen. Aus diesem Grunddie meisten Unix-Systeme ignorieren das Setuid-Bitwenn sie etwas entdecken.

Eine Möglichkeit, diese Implementierung abzusichern, wäre, dass der Kernel die Skriptdatei sperrt, bis der Interpreter sie geöffnet hat (beachten Sie, dass dies nicht nur das Aufheben der Verknüpfung oder das Überschreiben der Datei, sondern auch das Umbenennen von Verzeichnissen im Pfad verhindern muss). Aber Unix-Systeme scheuen sich in der Regel vor obligatorischen Sperren, und symbolische Links würden eine korrekte Sperrfunktion besonders schwierig und invasiv machen. Ich glaube nicht, dass das jemand so macht.

Einige Unix-Systeme (hauptsächlich OpenBSD, NetBSD und Mac OS X, die alle eine Kernel-Einstellung erfordern) implementierensicherer Setuid-ShebangVerwendung einer zusätzlichen Funktion: Der Pfad verweist auf die bereits im Dateideskriptor geöffnete Datei/dev/fd/NN(das Öffnen entspricht also ungefähr dem Öffnen von ). Viele Unix-Systeme (einschließlich Linux) haben Setuid-Skripte, aber keine./dev/fd/Ndup(N)/dev/fd

  1. Der Kernel öffnet die ausführbare Datei und stellt fest, dass sie mit beginnt #!. Nehmen wir an, der Dateideskriptor für die ausführbare Datei ist 3.
  2. Der Kernel öffnet den Interpreter.
  3. Der Kernel fügt /dev/fd/3die Argumentliste (als argv[1]) ein und führt den Interpreter aus.

Sven Maschecks Shebang-Seitehat viele Informationen über Shebang über Unices hinweg, einschließlichSetuid-Unterstützung.


Setuid-Dolmetscher

Nehmen wir an, Sie haben es geschafft, Ihr Programm als Root auszuführen, entweder weil Ihr Betriebssystem Setuid Shebang unterstützt oder weil Sie einen nativen Binär-Wrapper (wie z. B. sudo) verwendet haben. Haben Sie eine Sicherheitslücke geöffnet?VielleichtDas Problem hier istnichtüber interpretierte vs. kompilierte Programme. Das Problem ist, ob IhreLaufzeitsystemverhält sich sicher, wenn es mit Privilegien ausgeführt wird.

  • Jede dynamisch verknüpfte native binäre ausführbare Datei wird in gewisser Weise interpretiert vondynamischer Lader(z. B. /lib/ld.so), das die vom Programm benötigten dynamischen Bibliotheken lädt. Auf vielen Unix-Systemen können Sie den Suchpfad für dynamische Bibliotheken über die Umgebung konfigurieren ( LD_LIBRARY_PATHist ein gebräuchlicher Name für die Umgebungsvariable) und sogar zusätzliche Bibliotheken in alle ausgeführten Binärdateien laden ( ). Der Aufrufer des Programms kann beliebigen Code im Kontext dieses Programms ausführen, indem er (unter anderem) ein speziell gestaltetes in LD_PRELOADplatziert . Alle vernünftigen Systeme ignorieren die Variablen in Setuid-ausführbaren Dateien.libc.so$LD_LIBRARY_PATHLD_*

  • InMuschelnUmgebungsvariablen wie sh, csh und Ableitungen werden automatisch zu Shell-Parametern. Durch Parameter wie PATH, IFS, und viele mehr hat der Aufrufer des Skripts viele Möglichkeiten, beliebigen Code im Kontext des Shell-Skripts auszuführen. Einige Shells setzen diese Variablen auf vernünftige Standardwerte, wenn sie feststellen, dass das Skript mit Privilegien aufgerufen wurde, aber ich kenne keine bestimmte Implementierung, der ich vertrauen würde.

  • Die meisten Laufzeitumgebungen(ob nativ, Bytecode oder interpretiert) haben ähnliche Funktionen. Nur wenige treffen besondere Vorsichtsmaßnahmen in Setuid-Programmen, obwohl diejenigen, die nativen Code ausführen, oft nichts Ausgefalleneres tun als dynamisches Verknüpfen (bei dem Vorsichtsmaßnahmen getroffen werden).

  • Perlist eine bemerkenswerte Ausnahme. Esunterstützt explizit Setuid-Skripteauf sichere Weise. Tatsächlich kann Ihr Skript setuid ausführen, selbst wenn Ihr Betriebssystem das setuid-Bit in Skripten ignoriert. Dies liegt daran, dass Perl mit einem setuid-Root-Helfer ausgeliefert wird, der die erforderlichen Prüfungen durchführt und den Interpreter für die gewünschten Skripte mit den gewünschten Berechtigungen erneut aufruft. Dies wird imperlsecHandbuch. Früher waren Setuid-Perl-Skripte #!/usr/bin/suidperl -wTanstelle von erforderlich #!/usr/bin/perl -wT, aber auf den meisten modernen Systemen #!/usr/bin/perl -wTreicht dies aus.

Beachten Sie, dass die Verwendung einer nativen BinärdateiWrapper selbst tut nichts, um diese Probleme zu verhindern. Tatsächlich kann es die Situationschlechter, weil es Ihre Laufzeitumgebung daran hindern könnte, zu erkennen, dass es mit Privilegien aufgerufen wird, und seine Laufzeitkonfigurierbarkeit zu umgehen.

Ein nativer Binär-Wrapper kann ein Shell-Skript sicher machen, wenn der Wrapperdesinfiziert die Umgebung. Das Skript muss darauf achten, nicht zu viele Annahmen zu treffen (z. B. über das aktuelle Verzeichnis), aber das geht. Sie können hierfür sudo verwenden, vorausgesetzt, es ist so eingerichtet, dass die Umgebung bereinigt wird. Das Blacklisting von Variablen ist fehleranfällig, also immer Whitelisting. Stellen Sie bei sudo sicher, dass die env_resetOption aktiviert bzw. setenvdeaktiviert ist und env_filenur env_keepharmlose Variablen enthält.


Kurz und knapp:

  • Setuid Shebang ist unsicher, wird aber normalerweise ignoriert.
  • Wenn Sie ein Programm mit Berechtigungen ausführen (entweder über sudo oder setuid), schreiben Sie nativen Code oder Perl oder starten Sie das Programm mit einem Wrapper, der die Umgebung bereinigt (z. B. sudo mit der env_resetOption).

¹ Diese Diskussion gilt in gleicher Weise, wenn Sie „setgid“ durch „setuid“ ersetzen.Sie werden beide vom Linux-Kernel in Skripten ignoriert

Antwort2

Eine Möglichkeit, dieses Problem zu lösen, besteht darin, das Shell-Skript von einem Programm aus aufzurufen, das das Setuid-Bit verwenden kann.
Dies kann zum Beispiel sudo sein. So würden Sie dies beispielsweise in einem C-Programm erreichen:

#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;
 }

Speichern Sie es als setuid-test2.c.
Kompilieren Sie.
Führen Sie nun setuid für die Binärdatei dieses Programms aus:

su - nobody   
[enter password]  
chown nobody:nobody a.out  
chmod 4755 a.out  

Jetzt sollten Sie es ausführen können und sehen, dass Ihr Skript ohne Berechtigungen ausgeführt wird.
Aber auch hier müssen Sie entweder den Skriptpfad fest codieren oder ihn als Befehlszeilenargument an die obige EXE übergeben.

Antwort3

Ich stelle einigen Skripten, die im selben Boot sitzen, das folgende Präfix voran:

#!/bin/sh
[ "root" != "$USER" ] && exec sudo $0 "$@"

setuidBeachten Sie, dass hierbei nicht die aktuelle Datei verwendet , sondern einfach mit ausgeführt wird sudo.

Antwort4

Wenn dies aus irgendeinem Grund sudonicht verfügbar ist, können Sie ein schlankes Wrapper-Skript in C schreiben:

#include <unistd.h>
int main() {
    setuid(0);
    execle("/bin/bash","bash","/full/path/to/script",(char*) NULL,(char*) NULL);
}

Und sobald Sie es kompiliert haben, legen Sie es als setuidmit fest chmod 4511 wrapper_script.

Dies ähnelt einer anderen geposteten Antwort, führt das Skript jedoch in einer sauberen Umgebung aus und verwendet explizit /bin/bashanstelle der von aufgerufenen Shell system()und schließt so einige potenzielle Sicherheitslücken.

Beachten Sie, dass dadurch die Umgebung vollständig verworfen wird. Wenn Sie einige Umgebungsvariablen verwenden möchten, ohne Schwachstellen zu öffnen, müssen Sie wirklich nur verwenden sudo.

Natürlich möchten Sie sicherstellen, dass das Skript selbst nur vom Root-Benutzer geschrieben werden kann.

verwandte Informationen