Linux ignoriert das setuid¹-Bit in allen interpretierten ausführbaren Dateien (dh ausführbaren Dateien, die mit einer #!
Zeile beginnen). In den häufig gestellten Fragen zu comp.unix.questions werden die Sicherheitsprobleme mit setuid-Shell-Skripten erläutert. Es gibt zwei Arten von Problemen: shebang-bezogene und shell-bezogene; Ich gehe unten auf weitere Details ein.
Wenn Ihnen die Sicherheit egal ist und Sie setuid-Skripte zulassen möchten, müssen Sie unter Linux den Kernel patchen. Ab dem 3.x-Kernel muss install_exec_creds
der load_script
Funktion vor dem Aufruf von ein Aufruf hinzugefügt werden open_exec
, aber ich habe ihn nicht getestet.
Setuid Shebang
Die #!
Implementierung von shebang ( ) unterliegt einer Racebedingung:
- Der Kernel öffnet die ausführbare Datei und stellt fest, dass sie mit beginnt
#!
.
- Der Kernel schließt die ausführbare Datei und öffnet stattdessen den Interpreter.
- Der Kernel fügt den Pfad zum Skript in die Argumentliste ein (as
argv[1]
) und führt den Interpreter aus.
Wenn mit dieser Implementierung Setuid-Skripte zulässig sind, kann ein Angreifer ein beliebiges Skript aufrufen, indem er einen symbolischen Link zu einem vorhandenen Setuid-Skript erstellt, ausführt und anordnet, den Link zu ändern, nachdem der Kernel Schritt 1 ausgeführt hat und bevor der Interpreter zu ausgeführt hat Eröffnung seines ersten Arguments. Aus diesem Grund ignorieren die meisten Unices das Setuid-Bit, wenn sie einen Shebang erkennen.
Eine Möglichkeit, diese Implementierung zu sichern, besteht darin, dass der Kernel die Skriptdatei sperrt, bis der Interpreter sie geöffnet hat (beachten Sie, dass dies nicht nur das Aufheben oder Überschreiben der Verknüpfung der Datei, sondern auch das Umbenennen eines Verzeichnisses im Pfad verhindern muss). Unix-Systeme scheuen jedoch in der Regel obligatorische Sperren, und symbolische Verknüpfungen würden eine korrekte Sperrfunktion besonders schwierig und invasiv machen. Ich glaube nicht, dass es jemand so macht.
Einige Unix-Systeme (hauptsächlich OpenBSD, NetBSD und Mac OS X, für die alle eine Kernel-Einstellung erforderlich ist) implementieren Secure Setuid Shebang mit einer zusätzlichen Funktion: Der Pfad bezieht sich auf die Datei, die bereits im Dateideskriptor N geöffnet ist (also wird geöffnet) ungefähr äquivalent zu ). Viele Unix-Systeme (einschließlich Linux) haben aber keine setuid-Skripte./dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
- Der Kernel öffnet die ausführbare Datei und stellt fest, dass sie mit beginnt
#!
. Angenommen, der Dateideskriptor für die ausführbare Datei lautet 3.
- Der Kernel öffnet den Interpreter.
- Der Kernel fügt
/dev/fd/3
die Argumentliste (as argv[1]
) ein und führt den Interpreter aus.
Die shebang-Seite von Sven Mascheck enthält viele Informationen zu shebang across unices, einschließlich der Unterstützung von setuid .
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 sudo
) verwendet haben. Haben Sie eine Sicherheitslücke geöffnet? Vielleicht . Hier geht es nicht um interpretierte oder kompilierte Programme. Das Problem ist, ob sich Ihr Laufzeitsystem sicher verhält, wenn es mit Berechtigungen ausgeführt wird.
Jede dynamisch verknüpfte native ausführbare Binärdatei wird auf eine Weise vom Dynamic Loader (z. B. /lib/ld.so
) interpretiert , der 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 gebräuchlicher Name für die Umgebungsvariable) und sogar zusätzliche Bibliotheken in alle ausgeführten Binärdateien laden ( LD_PRELOAD
). Die Aufrufer des Programms kann in diesem Programm Kontext beliebigen Code auszuführen , indem er eine speziell gestaltete Platzierung libc.so
in $LD_LIBRARY_PATH
(unter anderem Taktik). Alle vernünftigen Systeme ignorieren die LD_*
Variablen in den ausführbaren Dateien von setuid.
In Shells wie sh, csh und Derivaten werden Umgebungsvariablen automatisch zu Shell-Parametern. Durch Parameter wie PATH
, IFS
und vieles mehr, hat der Aufrufer des Skripts viele Möglichkeiten , beliebigen Code in den Shell - Skripten Kontext auszuführen. Einige Shells setzen diese Variablen auf vernünftige Standardeinstellungen, wenn sie feststellen, dass das Skript mit Berechtigungen aufgerufen wurde, aber ich weiß nicht, dass es eine bestimmte Implementierung gibt, der ich vertrauen würde.
Die meisten Laufzeitumgebungen (ob native, Bytecode oder interpretiert) haben ähnliche Funktionen. Nur wenige Benutzer treffen spezielle Vorsichtsmaßnahmen in setuid-ausführbaren Dateien, obwohl diejenigen, die systemeigenen Code ausführen, häufig nichts Schöneres tun als dynamisches Verknüpfen (was Vorsichtsmaßnahmen erfordert).
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. Dies liegt daran, dass Perl mit einem setuid-Root-Helfer geliefert wird, der die erforderlichen Überprüfungen durchführt und den Interpreter für die gewünschten Skripte mit den gewünschten Berechtigungen erneut aufruft. Dies wird im perlsec- Handbuch erklärt. Früher brauchte man #!/usr/bin/suidperl -wT
stattdessen setuid-Perl-Skripte #!/usr/bin/perl -wT
, aber auf den meisten modernen Systemen #!/usr/bin/perl -wT
ist dies ausreichend.
Beachten Sie, dass die Verwendung eines systemeigenen Binär- Wrappers nichts an sich bewirkt, um diese Probleme zu vermeiden . Tatsächlich kann dies die Situation verschlimmern , da Ihre Laufzeitumgebung möglicherweise nicht erkennt, dass sie mit Berechtigungen aufgerufen wird, und die Laufzeitkonfigurierbarkeit umgeht.
Ein nativer binärer Wrapper kann ein Shell-Skript sicher machen, wenn der Wrapper die Umgebung bereinigt . Das Skript muss darauf achten, nicht zu viele Annahmen zu machen (zB über das aktuelle Verzeichnis), aber das geht. Sie können sudo dafür verwenden, sofern es so eingerichtet ist, dass die Umgebung bereinigt wird. Das Blacklisting von Variablen ist fehleranfällig, daher immer eine Whitelist. Stellen Sie mit sudo sicher, dass die env_reset
Option aktiviert und deaktiviert setenv
ist env_file
und env_keep
nur harmlose Variablen enthält.
TL, DR:
- Setuid shebang ist unsicher, wird aber normalerweise ignoriert.
- Wenn Sie ein Programm mit Berechtigungen ausführen (entweder über sudo oder setuid), schreiben Sie systemeigenen Code oder Perl oder starten Sie das Programm mit einem Wrapper, der die Umgebung bereinigt (z. B. sudo mit der
env_reset
Option).
¹ Diese Diskussion gilt auch, wenn Sie "setuid" durch "setgid" ersetzen. Beide werden vom Linux-Kernel in Skripten ignoriert
suidperl
suidperl
perl5110delta:> "suidperl" wurde entfernt wie von Perl 5.11 (5.12 stable) entfernt worden ist . Früher wurde ein Mechanismus zum Emulieren von setuid-Berechtigungsbits auf Systemen bereitgestellt, die dies nicht ordnungsgemäß unterstützen. perl5120delta:> "suidperl" ist nicht mehr Teil von Perl. Früher wurde ein Mechanismus zum Emulieren von setuid-Berechtigungsbits auf Systemen bereitgestellt, die dies nicht ordnungsgemäß unterstützen.Eine Möglichkeit, dieses Problem zu lösen, besteht darin, das Shell-Skript von einem Programm aus aufzurufen, das das setuid-Bit verwenden kann.
Es ist so etwas wie Sudo. So würden Sie dies beispielsweise in einem C-Programm ausführen:
Speichern Sie es als setuid-test2.c. Jetzt
kompiliere
die setuid in diesem Programm binär:
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.
quelle
PATH
undLD_LIBRARY_PATH
sind offensichtliche Vektoren. Einige Shells ausführen$ENV
oder$BASHENV
oder ,~/.zshenv
noch bevor sie das Skript richtigen beginnen Ausführung, so dass Sie nicht von dieser überhaupt aus dem Skript schützen. Die einzige sichere Möglichkeit, ein Shell-Skript mit Berechtigungen aufzurufen, besteht darin , die Umgebung zu bereinigen . Sudo weiß, wie man es sicher macht. Schreiben Sie also keinen eigenen Wrapper, sondern verwenden Sie sudo .LD_LIBRARY_PATH
unter anderem, wenn es auf das setuid-Bit stößt.system
, ist es möglicherweise einfacher (und effizienter), eine derexec
Familien zu verwenden - am wahrscheinlichstenexecve
. Auf diese Weise erstellen Sie keinen neuen Prozess und starten keine Shell. Sie können Argumente weiterleiten (vorausgesetzt, Ihr privilegiertes Skript kann sicher mit Argumenten umgehen).Ich stelle ein paar Skripte voran, die sich in diesem Boot befinden:
Beachten Sie, dass dies nicht verwendet,
setuid
sondern einfach die aktuelle Datei mit ausführtsudo
.quelle
sudo
Eingabeaufforderung ausgegeben. (Für mich ist es der springende Punkt bei setuid, Dinge als root laufen zu lassen, ohne sudo zu benötigen.)Wenn Sie einen Anruf vermeiden möchten,
sudo some_script
können Sie Folgendes tun:SETUID-Programme müssen mit äußerster Sorgfalt entworfen werden, da sie mit Root-Rechten ausgeführt werden und die Benutzer eine große Kontrolle über sie haben. Sie müssen alles auf geistige Gesundheit überprüfen. Sie können es nicht mit Skripten machen, weil:
sed
,awk
usw. müssten ebenfalls überprüft werdenBitte beachten Sie, dass
sudo
einige Sicherheitsüberprüfungen vorhanden sind, diese jedoch nicht ausreichen. Überprüfen Sie jede Zeile in Ihrem eigenen Code.Als letzte Anmerkung: Erwägen Sie die Verwendung von Funktionen. Mit ihnen können Sie einem Prozess, der als Benutzer ausgeführt wird, spezielle Berechtigungen zuweisen, für die normalerweise Root-Berechtigungen erforderlich sind. Beispielsweise
ping
muss das Netzwerk zwar manipuliert werden, es muss jedoch keinen Zugriff auf Dateien haben. Ich bin mir jedoch nicht sicher, ob sie vererbt werden.quelle
/ust/bin/env
sollte sein/usr/bin/env
.Sie können einen Alias für sudo + den Namen des Skripts erstellen. Das ist natürlich noch aufwändiger, da Sie dann auch einen Alias einrichten müssen, aber Sie müssen nicht sudo eingeben.
Wenn Sie jedoch nichts gegen schreckliche Sicherheitsrisiken haben, verwenden Sie eine setuid-Shell als Interpreter für das Shell-Skript. Ich weiß nicht, ob das für dich funktionieren wird, aber ich denke, es könnte sein.
Lassen Sie mich jedoch sagen, dass ich davon abraten würde. Ich erwähne es nur zu Bildungszwecken ;-)
quelle
rm -rf /
(und andere Befehle aus der Serie DON'T DO IT AT HOME ).super [-r reqpath] command [args]
Mit Super können bestimmte Benutzer Skripte (oder andere Befehle) so ausführen, als wären sie root. oder es kann die uid-, gid- und / oder ergänzenden Gruppen auf Befehlsbasis festlegen, bevor der Befehl ausgeführt wird. Es soll eine sichere Alternative zu Skripten sein, die setuid root verwenden. Mit Super können normale Benutzer auch Befehle zur Ausführung durch andere Benutzer bereitstellen. Diese werden mit der UID, der GID und den Gruppen des Benutzers ausgeführt, der den Befehl anbietet.
Super durchsucht eine "super.tab" -Datei, um festzustellen, ob der Benutzer den angeforderten Befehl ausführen darf. Wenn die Berechtigung erteilt wurde, führt super pgm [args] aus, wobei pgm das Programm ist, das diesem Befehl zugeordnet ist. (Die Ausführung von Root ist standardmäßig zulässig, kann jedoch weiterhin verweigert werden, wenn eine Regel Root ausschließt. Normalen Benutzern ist die Ausführung standardmäßig nicht gestattet.)
Wenn der Befehl eine symbolische Verknüpfung (oder auch eine feste Verknüpfung) zum Superprogramm ist, entspricht die Eingabe von% command args der Eingabe von% super command args (Der Befehl darf nicht super sein, oder super erkennt nicht, dass er über a aufgerufen wird Verknüpfung.)
http://www.ucolick.org/~will/RUE/super/README
http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html
quelle
Wenn aus irgendeinem Grund
sudo
nicht verfügbar ist, können Sie ein Thin-Wrapper-Skript in C schreiben:Und sobald Sie es kompiliert haben, setzen Sie es wie
setuid
mitchmod 4511 wrapper_script
.Dies ähnelt einer anderen veröffentlichten Antwort, führt das Skript jedoch in einer sauberen Umgebung aus und verwendet explizit
/bin/bash
anstelle der von aufgerufenen Shellsystem()
, wodurch einige potenzielle Sicherheitslücken geschlossen werden.Beachten Sie, dass dies die Umgebung vollständig verwirft. Wenn Sie einige Umgebungsvariablen verwenden möchten, ohne Sicherheitslücken zu öffnen, müssen Sie wirklich nur verwenden
sudo
.Natürlich möchten Sie sicherstellen, dass das Skript selbst nur von root geschrieben werden kann.
quelle
Ich habe diese Frage zum ersten Mal gefunden, ohne von allen Antworten überzeugt zu sein. Hier ist eine viel bessere, mit der Sie auch Ihr Bash-Skript vollständig verschleiern können, wenn Sie dazu geneigt sind!
Es sollte selbsterklärend sein.
Dann rennst du
quelle