GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Setuid für Shell-Skripte zulassen?

Die setuid Permission-Bit weist Linux an, ein Programm mit der effektiven Benutzer-ID des Eigentümers anstelle des Ausführenden 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

Wikipedia sagt:

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

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

Wenn nicht, gibt es eine allgemeine Problemumgehung für dieses Problem? Meine aktuelle Lösung besteht darin, ein sudoers hinzuzufügen Eintrag, um ALL zuzulassen mit NOPASSWD ein bestimmtes Skript unter dem Benutzer ausführen, unter dem es ausgeführt werden soll um die Passwortabfrage zu vermeiden. Der größte Nachteil dabei ist die Notwendigkeit eines sudoers Eintrag jedes Mal, wenn ich dies tun möchte, und die Notwendigkeit für den Aufrufer, sudo some-script auszuführen statt nur some-script

Akzeptierte Antwort:

Linux ignoriert das setuid¹-Bit bei allen interpretierten ausführbaren Dateien (d. h. ausführbaren Dateien, die mit einem #! beginnen Linie). Die häufig gestellten Fragen zu comp.unix.questions erklären die Sicherheitsprobleme mit setuid-Shell-Skripten. Diese Probleme sind von zweierlei Art:Shebang-bezogen und Schalen-bezogen; Auf weitere Details gehe ich weiter unten 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 meiner Meinung nach einen Aufruf zu install_exec_creds hinzufügen im load_script Funktion, vor dem Aufruf von open_exec , aber ich habe es nicht getestet.

Setuid Kram

Der Art und Weise, wie Shebang (#! ) wird typischerweise implementiert:

  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 bestehenden setuid-Skript erstellt, es ausführt und den Link ändert, nachdem der Kernel Schritt 1 ausgeführt hat und bevor der Interpreter dazu kommt Eröffnung seines ersten Arguments. Aus diesem Grund ignorieren die meisten Unices das setuid-Bit wenn sie einen Kram entdecken.

Eine Möglichkeit, diese Implementierung zu sichern, 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 eines Verzeichnisses im Pfad verhindern muss). Aber Unix-Systeme neigen dazu, sich vor obligatorischen Sperren zu scheuen, und symbolische Links würden eine korrekte Sperrfunktion besonders schwierig und invasiv machen. Ich glaube nicht, dass das irgendjemand so macht.

Einige wenige Unix-Systeme (hauptsächlich OpenBSD, NetBSD und Mac OS X, die alle eine aktivierte Kernel-Einstellung erfordern) implementieren sicheres setuid-Shebang mit einem zusätzlichen Feature:dem Pfad /dev/fd/N bezieht sich auf die bereits geöffnete Datei im Dateideskriptor N (Also öffnen Sie /dev/fd/N entspricht in etwa dup(N) ). Viele Unix-Systeme (einschließlich Linux) haben /dev/fd aber keine setuid-Skripte.

  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/3 ein die Argumentliste (als argv[1] ) und führt den Interpreter aus.
Verwandte:Welches sind die speziellen Parameter/Variablen der (Bash-)Shell?

Die Shebang-Seite von Sven Mascheck hat eine Menge Informationen über Shebang über Unices hinweg, einschließlich Setuid-Unterstützung.

Setuid-Interpreter

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ären Wrapper (wie sudo) verwendet haben ). Haben Sie eine Sicherheitslücke geöffnet? Vielleicht . Das Problem hier ist nicht über interpretierte vs. kompilierte Programme. Das Problem ist, ob Ihr Laufzeitsystem verhält sich sicher, wenn es mit Privilegien ausgeführt wird.

  • Jede dynamisch verknüpfte native ausführbare Binärdatei wird in gewisser Weise vom dynamischen Ladeprogramm interpretiert (zB /lib/ld.so ), die die vom Programm benötigten dynamischen Bibliotheken lädt. Auf vielen Unices können Sie den Suchpfad für dynamische Bibliotheken über die Umgebung konfigurieren (LD_LIBRARY_PATH ist ein allgemeiner Name für die Umgebungsvariable) und lädt sogar zusätzliche Bibliotheken in alle ausgeführten Binärdateien (LD_PRELOAD ). Der Aufrufer des Programms kann beliebigen Code im Kontext dieses Programms ausführen, indem er eine speziell gestaltete libc.so platziert in $LD_LIBRARY_PATH (neben anderen Taktiken). Alle vernünftigen Systeme ignorieren den LD_* Variablen in ausführbaren setuid-Dateien.

  • In Schalen wie sh, csh und Derivate werden Umgebungsvariablen 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 weiß nicht, ob es eine bestimmte Implementierung gibt, der ich vertrauen würde.

  • Die meisten Laufzeitumgebungen (egal ob nativ, Bytecode oder interpretiert) haben ähnliche Eigenschaften. Nur wenige treffen besondere Vorsichtsmaßnahmen in ausführbaren setuid-Dateien, obwohl diejenigen, die nativen Code ausführen, oft nichts Ausgefalleneres tun als dynamisches Linken (was Vorsichtsmaßnahmen trifft).

  • Perl ist eine bemerkenswerte Ausnahme. Es unterstützt ausdrücklich setuid-Skripte auf sichere Weise. Tatsächlich kann Ihr Skript setuid ausführen, selbst wenn Ihr Betriebssystem das setuid-Bit in Skripten ignoriert. Das liegt daran, dass Perl mit einem Setuid-Root-Hilfsprogramm ausgeliefert wird, das die notwendigen Prüfungen durchführt und den Interpreter für die gewünschten Skripte mit den gewünschten Privilegien erneut aufruft. Dies wird im perlsec-Handbuch erklärt. Früher benötigten Setuid-Perl-Skripte #!/usr/bin/suidperl -wT statt #!/usr/bin/perl -wT , aber auf den meisten modernen Systemen #!/usr/bin/perl -wT ist ausreichend.

Beachten Sie, dass die Verwendung eines nativen binären Wrappers nichts tut, um diese Probleme zu verhindern . Tatsächlich kann es die Situation schlimmer machen , 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 Wrapper die Umgebung bereinigt . Das Skript muss darauf achten, nicht zu viele Annahmen zu treffen (z. B. über das aktuelle Verzeichnis), aber das geht. Sie können dafür sudo verwenden, vorausgesetzt, es ist so eingerichtet, dass es die Umgebung bereinigt. Das Blacklisting von Variablen ist fehleranfällig, also immer Whitelisting. Stellen Sie mit sudo sicher, dass die Datei env_reset Option eingeschaltet ist, dass setenv ausgeschaltet ist, und diese env_file und env_keep nur harmlose Variablen enthalten.

Verwandte:Wie kann man Anführungszeichen in der Shell entkommen?

TL,DR:

  • Setuid shebang ist unsicher, wird aber normalerweise ignoriert.
  • Wenn Sie ein Programm mit Privilegien 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 dem env_reset Option).

¹ Diese Diskussion gilt gleichermaßen, wenn Sie „setgid“ durch „setuid“ ersetzen; sie werden beide vom Linux-Kernel in Skripten ignoriert


Linux
  1. Shell-Skripte über eine Website ausführen?

  2. Dateierweiterungen für Unix-Shell-Skripte?

  3. Gemeinsame Nutzung von Variablen über mehrere Shell-Skripte hinweg?

  4. Wie testet man die Posix-Konformität von Shell-Skripten?

  5. Lange Befehle in Shell-Skripten aufteilen?

So erstellen Sie Shell-Skripte

Arrays in Shell-Skripten

Wie verwende ich if-else in Shell-Skripten?

Die for-Schleife in Shell-Skripten verstehen

Die While-Schleife in Shell-Skripten

Führen Sie alle Shell-Skripte im Ordner aus