Das setuid-Bit kann für eine ausführbare Datei festgelegt werden, sodass das Programm beim Ausführen die Berechtigungen des Eigentümers der Datei anstelle des tatsächlichen Benutzers hat, sofern diese unterschiedlich sind. Dies ist der Unterschied zwischen der effektiven UID (Benutzer-ID) und der realen UID.
Einige gängige Dienstprogramme, wie z. B. passwd
, sind im Besitz von root und werden so konfiguriert, dass sie nicht passwd
benötigt werden ( Zugriff /etc/shadow
nur für root möglich).
Die beste Strategie dabei ist, sofort das zu tun, was Sie als Superuser tun müssen, und dann die Berechtigungen zu verringern, damit Fehler oder Missbrauch beim Ausführen von root weniger wahrscheinlich sind. Dazu setzen Sie die effektive Benutzer-ID des Prozesses auf die tatsächliche Benutzer-ID. In POSIX C:
#define _POSIX_C_SOURCE 200112L // Needed with glibc (e.g., linux).
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void report (uid_t real) {
printf (
"Real UID: %d Effective UID: %d\n",
real,
geteuid()
);
}
int main (void) {
uid_t real = getuid();
report(real);
seteuid(real);
report(real);
return 0;
}
Die relevanten Funktionen, die in den meisten höheren Sprachen gleichwertig sein sollten, wenn sie auf POSIX-Systemen häufig verwendet werden:
getuid()
: Holen Sie sich die echte UID.
geteuid()
: Holen Sie sich die effektive UID.
seteuid()
: Stellen Sie die effektive UID ein.
Sie können nichts mit dem letzten tun, das für die echte UID unangemessen ist, außer insofern, als das Setuid-Bit für die ausführbare Datei gesetzt wurde . Um dies zu versuchen, kompilieren Sie gcc test.c -o testuid
. Sie müssen dann mit Privilegien:
chown root testuid
chmod u+s testuid
Der letzte setzt das setuid-Bit. Wenn Sie jetzt ./testuid
als normaler Benutzer ausgeführt werden, wird der Prozess standardmäßig mit der effektiven UID 0 root ausgeführt.
Was ist mit Skripten?
Dies ist von Plattform zu Plattform unterschiedlich , aber unter Linux können Dinge, die einen Interpreter, einschließlich Bytecode, erfordern, das setuid-Bit nur verwenden, wenn es auf dem Interpreter gesetzt ist (was sehr, sehr dumm wäre). Hier ist ein einfaches Perl-Skript, das den obigen C-Code nachahmt:
#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);
print "Real UID: $< Effective UID: $>\n";
$> = $<; # Not an ASCII art greedy face, but genuine perl...
print "Real UID: $< Effective UID: $>\n";
Getreu seinen * nixy-Wurzeln hat Perl spezielle Variablen für effektive uid ( $>
) und echte uid ( $<
) eingebaut . Wenn Sie jedoch dasselbe versuchen chown
und chmod
es mit der kompilierten (aus C, vorheriges Beispiel) ausführbaren Datei verwenden, macht es keinen Unterschied. Das Skript kann keine Berechtigungen erhalten.
Die Antwort auf diese Frage ist, eine setuid-Binärdatei zu verwenden, um das Skript auszuführen:
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
if (argc < 2) {
puts("Path to perl script required.");
return 1;
}
const char *perl = "perl";
argv[0] = (char*)perl;
return execv("/usr/bin/perl", argv);
}
Kompilieren Sie dies gcc --std=c99 whatever.c -o perlsuid
dann chown root perlsuid && chmod u+s perlsuid
. Sie können jetzt jedes Perl-Skript mit einer effektiven UID von 0 ausführen , unabhängig davon, wem es gehört.
Eine ähnliche Strategie funktioniert mit PHP, Python usw. Aber ...
# Think hard, very important:
>_< # Genuine ASCII art "Oh tish!" face
BITTE BITTE Lass sowas NICHT herumliegen . Höchstwahrscheinlich möchten Sie den Namen des Skripts tatsächlich als absoluten Pfad kompilieren , dh den gesamten Code in main()
durch Folgendes ersetzen :
const char *args[] = { "perl", "/opt/suid_scripts/whatever.pl" }
return execv("/usr/bin/perl", (char * const*)args);
Sie stellen sicher, dass alle /opt/suid_scripts
Inhalte für Benutzer ohne Rootberechtigung schreibgeschützt sind. Andernfalls könnte jemand etwas gegen etwas eintauschen whatever.pl
.
Beachten Sie außerdem, dass in vielen Skriptsprachen Umgebungsvariablen die Art und Weise ändern können, in der sie ein Skript ausführen . Beispielsweise kann eine Umgebungsvariable dazu führen, dass eine vom Aufrufer bereitgestellte Bibliothek geladen wird, sodass der Aufrufer beliebigen Code als Root ausführen kann. Wenn Sie also nicht wissen, dass sowohl der Interpreter als auch das Skript selbst gegenüber allen möglichen Umgebungsvariablen robust sind, TUN Sie DIESES NICHT .
Also, was soll ich stattdessen tun?
Eine sicherere Möglichkeit, einem Benutzer ohne Rootberechtigung die Ausführung eines Skripts als Rootberechtigung zu ermöglichen, besteht darin, eine sudo- Regel hinzuzufügen und den Benutzer ausführen zu lassen sudo /path/to/script
. Sudo entfernt die meisten Umgebungsvariablen und ermöglicht es dem Administrator, genau auszuwählen, wer den Befehl mit welchen Argumenten ausführen darf. Siehe So führen Sie ein bestimmtes Programm als root ohne Kennworteingabeaufforderung aus zum Beispiel.
-privileged
Shell aufgerufensuid root
werden. Wenn sie von einem verantwortlichen Skript aufgerufen werden, können sie auch sicher auf diese Weise aufgerufen werden. Ich befürchte jedoch, dass die Vorstellung eines verantwortungsvollen Skripts in der realen Welt ein bisschen wie ein Wunschtraum ist. Wie auch immer, es ist wahrscheinlich erwähnenswert, wie wichtig es ist, Schreibzugriffe jeglicher Art zu vermeiden, wenn dies bei erhöhten Berechtigungen möglich ist ...-privileged
Shell" und "Responsible Script" nicht. Möchten Sie eine weitere Antwort zu Muscheln geben? Ich kann dir das Häkchen natürlich nicht versprechen;) Es gibt nicht viele gute Gründe, dies zu tun -sudo
ist eine viel bessere Option, wenn möglich - ich habe es als generische Antwort geschrieben, die aus einer frühen Frage über die Authentifizierung von Systemkennwörtern in PHP stammt .sudo
- halte ichsudo
als psychotisch , dass sie vorgibt , nicht zu seinroot
. Sie können sogar Muschelkugeln in Ihre Muschel legensudoers
.su
ist meiner meinung nach für scripting zwecke besser,sudo
ist aber gut für live anwendungen. Aber weder ist so explizit wie ein Skript mit einem#!/bin/ksh -p
bangline oder was auch immer dassuid ksh
in$PATH
ist.Ja, das kannst du, aber es ist wahrscheinlich eine sehr schlechte Idee . Normalerweise setzen Sie das SUID-Bit nicht direkt in Ihrer ausführbaren Datei, sondern verwenden ein sudo (8) oder su (1) , um sie auszuführen (und begrenzen, wer sie ausführen kann).
Beachten Sie jedoch, dass es sehr viele Sicherheitsprobleme gibt, wenn reguläre Benutzer Programme (und insbesondere Skripte!) Als Root ausführen. Die meisten von ihnen müssen dies tun, es sei denn, das Programm wurde speziell und sehr sorgfältig dafür geschrieben, und böswillige Benutzer könnten es verwenden, um auf einfache Weise die Root-Shell zu erhalten.
Selbst wenn Sie dies tun würden, wäre es eine gute Idee, zuerst ALLE Eingaben für das Programm zu bereinigen, das Sie als Root ausführen möchten, einschließlich der Umgebung, der Befehlszeilenparameter, STDIN und aller von ihm verarbeiteten Dateien sowie Daten, die von Netzwerkverbindungen stammen es öffnet sich usw. usw. Es ist extrem schwer und noch schwerer, es richtig zu machen.
Beispielsweise können Sie Benutzern erlauben, dass nur einige Dateien mit dem Editor bearbeitet werden. Der Editor ermöglicht jedoch die Befehlsausführung externer Hilfsprogramme oder das Unterbrechen, sodass Benutzer die Root-Shell nach Belieben ausführen können. Oder Sie führen Shell-Skripte aus, die für Sie sehr sicherheitsrelevant sind, aber der Benutzer kann sie mit geändertem $ IFS oder anderen Umgebungsvariablen ausführen, um das Verhalten vollständig zu ändern. Oder es könnte ein PHP-Skript sein, das "ls" ausführen soll, aber der Benutzer führt es mit modifiziertem $ PATH aus und lässt es so eine Shell ausführen, die er "ls" nennt. Oder Dutzende anderer Sicherheitsprobleme.
Wenn das Programm wirklich einen Teil seiner Arbeit als root ausführen muss, ist es wahrscheinlich am besten, es so zu ändern, dass es als normaler Benutzer ausgeführt wird, aber nur den Teil auszuführen (nachdem so viel wie möglich bereinigt wurde), der unbedingt root durch das Hilfsprogramm suid benötigt.
Beachten Sie, dass es eine schlechte Idee ist, selbst wenn Sie Ihren lokalen Benutzern vollständig vertrauen (z. B. geben Sie ihnen ein Root-Passwort), da JEDER von ihnen eine unbeabsichtigte Sicherheitsüberprüfung durchführt (z. B. ein PHP-Skript online oder ein schwaches Passwort) (was auch immer) ermöglicht es einem entfernten Angreifer plötzlich, die gesamte Maschine vollständig zu gefährden.
quelle
man sh
- und selbst das tut ein nichtcommand -p env -i ...
. Es ist doch ziemlich schwer zu tun. Dennoch , wenn es richtig gemacht, für die explizite Zwecke kann es besser sein,suid
einen kompetenten Dolmetscher als zu verwendensu
odersudo
- wie das Verhalten der beiden wird man immer außerhalb der Kontrolle des Skripts sein (wenn auchsu
weniger wahrscheinlich Kurve Bälle zu werfen , da es dazu neigt , etwas weniger verrückt sein) . Das Bündeln des gesamten Pakets ist die einzig sichere Wette - es ist nur besser, wenn Sie sicher sind , dass es alles ist.