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

Warum ist SUID für Shell-Skripte deaktiviert, aber nicht für Binärdateien?

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 alle modernen Unices das setuid-Bit, wenn sie einen Shebang 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 jemand so macht.

Einige Unix-Systeme implementieren sicheres Setuid-Shebang mit einer zusätzlichen Funktion: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) ).

  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.

Alle modernen Unix-Varianten einschließlich Linux implementieren /dev/fd , aber die meisten erlauben keine setuid-Skripte. OpenBSD, NetBSD und Mac OS X unterstützen es, wenn Sie eine nicht standardmäßige Kernel-Einstellung aktivieren. Unter Linux haben Leute Patches geschrieben, um dies zu ermöglichen, aber diese Patches wurden nie zusammengeführt. Die Shebang-Seite von Sven Mascheck enthält viele Informationen über Shebang über Unices hinweg, einschließlich Setuid-Unterstützung.

Darüber hinaus haben Programme, die mit erhöhten Rechten ausgeführt werden, inhärente Risiken, die in höheren Programmiersprachen normalerweise schwerer zu kontrollieren sind, es sei denn, der Interpreter wurde speziell dafür entwickelt. Der Grund dafür ist, dass der Initialisierungscode der Programmiersprachenlaufzeit möglicherweise Aktionen mit erhöhten Rechten ausführt, basierend auf Daten, die vom Aufrufer mit niedrigeren Rechten geerbt wurden, bevor der eigene Code des Programms die Möglichkeit hatte, diese Daten zu bereinigen. Die C-Laufzeit tut dem Programmierer sehr wenig, daher haben C-Programme eine bessere Gelegenheit, die Kontrolle zu übernehmen und Daten zu bereinigen, bevor etwas Schlimmes passieren kann.

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. Die Frage ist, ob sich Ihr Laufzeitsystem sicher verhält, wenn es mit Privilegien ausgeführt wird.

  • Jede dynamisch verknüpfte native binäre ausführbare Datei wird in gewisser Weise vom dynamischen Ladeprogramm interpretiert (z. B. /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 einen speziell gestalteten libc.so platziert in $LD_LIBRARY_PATH (neben anderen Taktiken). Alle vernünftigen Systeme ignorieren LD_* Variablen in ausführbaren setuid-Dateien.

  • In Shells wie sh, csh und Derivaten 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 (ob nativ, Bytecode oder interpretiert) haben ähnliche Funktionen. 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 explizit 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 brauchten 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är-Wrappers an sich nichts tut, um diese Probleme zu verhindern. Tatsächlich kann es die Situation verschlimmern, 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 der env_reset Option eingeschaltet ist, dass setenv ausgeschaltet ist, und dass env_file und env_keep nur harmlose Variablen enthalten.

Alle diese Überlegungen gelten gleichermaßen für alle Rechteerweiterungen:setuid, setgid, setcap.

Wiederverwertet von https://unix.stackexchange.com/questions/364/allow-setuid-on-shell-scripts/2910#2910


Vor allem weil

Viele Kernel leiden unter einer Race-Condition, die es Ihnen ermöglichen kann, das Shellscript gegen eine andere ausführbare Datei Ihrer Wahl auszutauschen, wenn der neu ausgeführte Prozess setuid geht und der Befehlsinterpreter gestartet wird. Wenn Sie hartnäckig genug sind, könnten Sie den Kernel theoretisch dazu bringen, jedes gewünschte Programm auszuführen.

sowie andere Gründe, die unter diesem Link gefunden werden (aber die Kernel-Race-Bedingung ist die schädlichste). Skripte werden natürlich anders geladen als Binärprogramme, und hier schleicht sich der Fehler ein.

Es könnte Sie amüsieren, diesen Artikel von Dr. Dobb aus dem Jahr 2001 zu lesen, der 6 Schritte zum Schreiben sicherer SUID-Shell-Skripte durchläuft, nur um Schritt 7 zu erreichen:

Lektion Sieben -- Verwenden Sie keine SUID-Shell-Skripte.

Selbst nach all unserer Arbeit ist es fast unmöglich, sichere SUIDshell-Skripte zu erstellen. (Auf den meisten Systemen ist dies nicht möglich.) Aufgrund dieser Probleme werden einige Systeme (z. B. Linux) SUID in Shellscripts nicht berücksichtigen.

Diese Geschichte spricht darüber, welche Varianten Korrekturen für die Rennbedingung hatten; die Liste ist länger als Sie denken ... aber von setuid-Skripten wird immer noch weitgehend abgeraten wegen anderer Probleme oder weil es einfacher ist, sie zu entmutigen, als sich daran zu erinnern, ob Sie auf einer sicheren oder unsicheren Variante laufen.

Das war damals ein Problem, das groß genug war, dass es aufschlussreich ist, darüber zu lesen, wie aggressiv Perl an die Kompensation herangegangen ist.


Linux
  1. Dateierweiterungen für Unix-Shell-Skripte?

  2. Linux – Warum funktioniert Locale Es_mx, aber nicht Es?

  3. Warum funktioniert das Parent Shell Here-Dokument nicht für Unterbefehle in Dash, aber Bash funktioniert?

  4. Warum erfordert „ls“ einen separaten Prozess zur Ausführung?

  5. Warum funktioniert Tomcat mit Port 8080, aber nicht mit 80?

Shell-Scripting für Anfänger – So schreiben Sie Bash-Scripts unter Linux

Warum funktioniert dieses „beim Lesen“ in einem Terminal, aber nicht in einem Shell-Skript?

Die for-Schleife in Shell-Skripten verstehen

Unit-Tests für Shell-Skripte

Warum sehe ich MSG_EOR für SOCK_SEQPACKET unter Linux nicht?

`ssh <host>` ist eine Login-Shell, aber `ssh <host> <command>` nicht?