Viele Anleitungen enthalten Befehle mit vorangestelltem sudo
. Sie blind zu übernehmen, kann gefährlich werden. Im folgenden Beitrag erfährst du, was das ist, wie es funktioniert und wie das Werkzeug zur Verbesserung der Sicherheit genutzt werden kann. Dieser richtet sich an Raspberry Pi Nutzer gleichermaßen wie alle anderen, die GNU/Linux auf PCs, Servern oder sonstigen Geräten einsetzen.
Warum arbeiten wir nicht einfach als Root/Admin?
Ein Nutzer sollte nur so viele Rechte besitzen, wie er benötigt – das ist seit Jahrzehnten ein bewährter Grundsatz. Wer im Alltag mit einem privilegierten Konto (root/Administrator) arbeitet, geht ein hohes Risiko ein. Immerhin hat jedes damit gestartete Programm uneingeschränkt volle Rechte auf dem gesamten System. Fehler oder Sicherheitslücken in der genutzten Software können damit weitreichende Folgen haben. Allerdings benötigt man für bestimmte Aufgaben volle Rechte: Beispielsweise die Installation von Software oder um Dienste (neu) zu starten – kurz alle Aufgaben, die sich global auf das System auswirken, statt nur den angemeldeten Benutzer. Wie macht man das, ohne ständig mit einem Root-Benutzer zu arbeiten?
Man könnte im Alltag einen normalen Nutzer verwenden und nur für die administrativen Aufgaben zu Root wechseln. Dafür existiert das GNU/Linux Werkzeug su
: Es meldet vereinfacht gesagt einen anderen Nutzer in der laufenden Sitzung an. Als Benutzer X angemeldet lässt sich so zeitweise eine Konsole mit Benutzer Y öffnen. Ohne Übergabe eines Benutzernamens öffnet su
eine Root-Shell.1 Das hat jedoch mehrere Nachteile. So landen eingegebene Befehle in der Bash-Historie von root, statt unserem eigenen Benutzer. Dies kann an verschiedenen Stellen problematisch sein – etwa wenn Programme Dateien in das Benutzerprofil ablegen. Ein Programm, dass nur an einer einzigen Stelle Root-Rechte benötigt (z.B. zum einmaligen Anlegen systemweiter Konfigurationsdateien), muss somit im ungünstigsten Falle ständig mit vollen Rechten laufen.
Nicht jeder Student sollte volle Root-Rechte haben – sudo regelt das
Ein weiteres Problem: Um su nutzen zu können, wird das Passwort des Nutzers root benötigt. Damit hat die betreffende Person uneingeschränkte Rechte. Das mag für Administratoren noch akzeptabel sein, bei Studenten beispielsweise schon schwieriger. Bereits Anfang der 1980er Jahre entstand sudo für das damals gängige Unix, um Root-Rechte für einzelne Befehle zu erlauben. Insbesondere jene, die keine oder eine überschaubare Gefahr für das System darstellen. Darunter könnten z.B. das Einspielen von Software-Aktualisierungen oder Neustarten von (harmlosen) Diensten fallen. Auf einem lokalen Arbeitsplatz/Test-PC wohl auch das Neustarten, was standardmäßig als normaler Benutzer nicht per Kommandozeile möglich ist. Das Konzept setzte sich durch, sodass sudo
auch zu GNU/Linux portiert wurde, nachdem Linux 1991 erschien.
u-labs@pi4:~ $ reboot
Call to Reboot failed: Interactive authentication required.
Sudo kann noch mehr: Das sind die wichtigsten Funktionen
Soll ein Befehl mit erhöhten Rechten ausgeführt werden, genügt es nach der einmaligen Einrichtung für den angemeldeten Benutzer meist, sudo
davor zu schreiben. Im Gegensatz zu su
entfällt die lästige manuelle An- und Abmeldung als Root. Intern passiert etwas ähnliches, das den Arbeitsfluss aus Nutzersicht nicht unterbricht. Außerdem landet alles im Bash-Verlauf des normalen Nutzers. Man kann sogar einstellen, ob zur Bestätigung ein Passwort eingegeben werden muss – wenn ja, in welchem Intervall.
Der größte Vorteil von sudo sind die umfangreichen Einstellungsmöglichkeiten, welche im Detail den Rahmen dieses Einstiegsbeitrages sprengen würden. Ich fokussiere mich daher im Folgenden auf die grundsätzliche Funktionsweise mit einfacheren Beispielen. Ebenfalls interessant können die Protokolle von sudo sein. Damit lässt sich nachvollziehen, welcher Nutzer sudo wofür genutzt hat. Oder nutzen wollte, da unberechtigte Aufrufe ebenfalls aufgezeichnet werden.
Wie kann ich sudo konfigurieren?
Grundsätzlich brauchst du dafür root-Rechte. Einige einsteigerfreundliche Distributionen sind automatisch so voreingestellt, dass sie dem von dir bei der Installation angelegten Nutzer automatisch Sudo-Rechte gewähren – hierzu zählt unter anderem das Raspberry Pi OS. Man kann es leicht wie folgt testen:
u-labs@pi5:~ $ sudo whoami
root
Möglicherweise werdet ihr bei manchen Distributionen zur Eingabe des Passworts eures Kontos aufgefordert. Falls root als Ausgabe erscheint, könnt ihr sudo verwenden. Andernfalls erscheint eine Fehlermeldung:
student@pi5:~$ sudo whoami
[sudo] password for student:
student is not in the sudoers file.
In diesem Falle bleibt dir nur die direkte Anmeldung mit dem root Benutzerkonto, um zumindest dein normales Konto erst einmal zu berechtigen. Wie das funktioniert, schauen wir uns im folgenden Abschnitt an. Anschließend kann die weitere, ggf. detailliertere Einrichtung von deinem regulären Nutzer geschehen.
Was erlaubt dir sudo? So konfigurierst du Berechtigungen
Die Haupt-Konfiguration erfolgt über /etc/sudoers
.2 Man sollte sie allerdings nicht direkt bearbeiten: Im Falle von (versehentlichen) Syntaxfehlern funktioniert sudo nicht mehr richtig. Um das zu reparieren, ist eine direkte Anmeldung als root nötig. Das kann aufwändiger werden, insbesondere falls es sich um ein entferntes System handelt, welches die Anmeldung als root zur Sicherheit verbietet. Daher besser das dafür vorgesehene Werkzeug visudo
verwenden: Es speichert Änderungen zuerst in eine temporäre Datei und prüft, ob man sich an die Regeln der Konfigurationssprache gehalten hat. Falls nein, lassen sich Fehler korrigieren, bevor diese in /etc/sudoers
landen:
Wie man am Name vermuten kann, verwendet visudo
standardmäßig den Texteditor vi
(bzw. heute eher vim
). Da die Umgebungsvariable EDITOR respektiert wird, startet es – je nach Konfiguration durch die Distribution und den Benutzer – möglicherweise einen anderen Editor, etwa Nano auf dem Raspberry Pi OS. visudo
muss als root aufgerufen werden.
sudo EDITOR=nano visudo
Bei vielen Distributionen findest du hier Voreinstellungen. Zwei davon sind dafür zuständig, dass wir auf einem frisch installierten Raspberry Pi OS mit unserem eigenen Benutzer ohne Passwort oder weitere Einstellungen sudo verwenden können:
%sudo ALL=(ALL:ALL) ALL
Damit darf jedes Mitglied der sudo Gruppe uneingeschränkt jegliche administrativen Befehle ausführen. Standardmäßig wird man jedoch nach dem Passwort des angemeldeten Nutzers gefragt. Das geschieht beim Raspberry Pi OS nicht, weil sudo zusätzlich alle Konfigurationsdateien in /etc/sudoers.d lädt. Dort wiederum legt der Einrichtungsassistent vom RPIOS die Datei /etc/sudoers.d/010_pi-nopasswd
an:
u-labs ALL=(ALL) NOPASSWD: ALL
Durch NOPASSWD: ALL
erlaubt es, alle Befehle ohne Passworteingabe sofort auszuführen. Grundsätzlich beginnt die Zeile mit einem Benutzername (hier u-labs) oder dem Name einer Gruppe (mit vorangestelltem Prozentzeichen: %sudo
im vorherigen Beispiel). Es folgen mögliche Einschränkungen auf den Rechnername (Host), Zielbenutzer/Gruppe, optional zusätzliche Anweisungen mit Doppelpunkt (etwa NOPASSWD:
) und schlussendlich den oder die Befehle. ALL dient als Platzhalter für keine Beschränkungen.
[Benutzer/Gruppe] [Rechnername]=[Zielbenutzer/Zielgruppe] [Optionen:] [Erlaubter Befehl]
Bereits bei diesem grundsätzlichen Aufbau der Regeln wird deutlich, dass sudo
viel mehr Möglichkeiten bietet, als nur einzelne Befehle mit Root-Rechten auszuführen. Man kann einem Benutzer A beispielsweise auch erlauben, bestimmte Befehle als Nutzer B zu starten. Ein Befehl kann ohne Eingabe des Passwortes erfolgen, für einen anderen (sensibleren) dagegen wird dies erzwungen.
Praktische & einfache Beispiele
Die Liste ließe sich fortsetzen, schauen wir uns stattdessen einfachere Regeln an konkreten Beispielen an. Ich habe dafür einen Benutzer namens student angelegt – ganz simpel mit useradd, sodass dieser keine besonderen Rechte besitzt. Auf dem Testsystem wurde ein Apache2 Webserver installiert und als Systemd-Dienst gestartet. Der student Benutzer darf den Dienst nicht neu starten – was allerdings sinnvoll sein könnte, etwa um auf einem Testsystem Konfigurationsänderungen anzuwenden.
student@pi5:~$ systemctl restart apache2
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
Authentication is required to restart 'apache2.service'.
Authenticating as: ,,, (u-labs)
Password:
student@pi5:~$ sudo systemctl restart apache2
[sudo] password for student:
Sorry, user student is not allowed to execute '/usr/bin/systemctl restart apache2' as root on pi5.
Um ihm dies mit sudo zu erlauben, genügt folgende Zeile:
student ALL=(root) NOPASSWD: /usr/bin/systemctl restart apache2
Damit darf er an jedem Rechner mit dieser Konfiguration als root ohne Passworteingabe den Befehl systemctl restart apache2
ausführen. Weder Neustart noch neu Anmelden sind dafür notwendig, die Änderung ist sofort wirksam:
student@pi5:~$ sudo systemctl restart apache2
student@pi5:~$ systemctl status apache2
● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; preset: enabled)
Active: active (running) since Mon 2024-05-13 23:49:12 CEST; 5s ago
Wichtig zu wissen: Sudo wertet den gesamten Befehl aus und erfordert eine exakte Übereinstimmung. Die Systemd-Unit von Apache2 ist ein Dienst (Service), daher könnten wir ihn vollqualifiziert über apache2.service
ansprechen. Unser student darf das allerdings nicht, weil wir ihm lediglich systemctl restart apache2
erlaubt haben:
student@pi5:~$ sudo systemctl restart apache2.service
[sudo] password for student:
Sorry, user student is not allowed to execute '/usr/bin/systemctl restart apache2.service' as root on pi5.
Dementsprechend sind andere Operationen wie z.B. systemctl stop apache2
ebenfalls verboten. Möchten wir Start & Stop ebenfalls erlauben, können mehrere Befehle mit Komma getrennt werden:
student ALL=(root) NOPASSWD: /usr/bin/systemctl restart apache2, /usr/bin/systemctl start apache2, /usr/bin/systemctl stop apache2
Solche und komplexere Muster lassen sich mit regulären Ausdrücken abbilden. Was sich zwischen ^ und $ befindet, wird als regulärer Ausdruck ausgewertet.3 Alle drei Systemd-Operationen für Apache lassen sich daher einfacher mit einem ODER (|) erlauben:
student ALL=(root) NOPASSWD: /usr/bin/systemctl ^(restart|start|stop) apache2$
Durch ein Ausrufezeichen lassen sich einzelne Befehle verbieten. Folgendes Beispiel erlaubt alle Systemd-Operationen, sodass alles zwischen systemctl
und apache2
stehen darf. Anschließend wird der Stop-Aufruf aber als einziger Verboten.
student ALL=(root) NOPASSWD: /usr/bin/systemctl ^(.+) apache2$, !/usr/bin/systemctl stop apache2
Sicherheit: Wie man die Regeln manchmal über Umwege umgehen kann
Dieses Szenario zeigt jedoch, wie gefährlich solche universellen Platzhalter sein können. Folgender Aufruf umgeht die Einschränkung:
student@pi5:~$ sudo systemctl stop ab apache2
Failed to stop ab.service: Unit ab.service not loaded.
student@pi5:~$ sudo systemctl status apache2
○ apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; preset: enabled)
Active: inactive (dead) since Tue 2024-05-14 00:13:19 CEST; 2s ago
Wie ist das möglich? Systemd akzeptiert den Namen mehrerer Dienste und führt in diesem Falle die Operation nacheinander auf alle aus. Fehlende Dienste verursachen keinen Abbruch, er fährt mit dem nächsten fort. Da nur systemctl stop apache2
explizit ausgeschlossen wurde (das wird wie erwartet verweigert), nicht aber weitere Dienste dazwischen, greift die Ausnahme nicht.
student@pi5:~$ sudo systemctl stop apache2
Sorry, user student is not allowed to execute '/usr/bin/systemctl stop apache2' as root on pi5.
Man sollte mit Platzhaltern und insbesondere Regex daher aufpassen. Falls notwendig, die gewünschten Optionen stattdessen auflisten. Das vorherige Beispiel mit entferntem stop, also /usr/bin/systemctl ^(restart|start) apache2$
, ist sicherer: Es erlaubt nur systemctl restart apache2
und systemctl start apache2
, sodass der Trick nicht funktioniert.
Die zweite Gefahr besteht darin, ganze Programme zu erlauben, die wiederum direkt oder indirekt das Ausbrechen ermöglichen. Ein Beispiel sind Texteditoren:
student ALL=(root) NOPASSWD: /usr/bin/nano
Damit darf der einfache Editor Nano als root gestartet werden. Der Editor hat somit unbegrenzte Schreibrechte auf dem gesamten System. Beispielsweise könnte er in /etc/sudoers.d
eine Konfigurationsdatei anlegen, die seinem Nutzer uneingeschränkt volle Rechte gibt. Oder bestehende Skripte überschreiben, die auf anderem Wege gewollt von root ausgeführt werden. Über mächtigere Editoren wie vim ist es sogar möglich, direkt Code (Shell, Python, …) auszuführen. GTFOBins sammelt derartige legitime Funktionen, die in Kombination mit weitreichenden sudo-Regeln zur Rechteausweitung missbraucht werden können.4
Es ist nicht zu unterschätzen, welche mächtigen und oft unerwarteten Funktionen in vermeintlich simpler Software stecken können. Ein Beispiel ist tar zum Entpacken der gleichnamigen Archive. Dies bietet Checkpoints, um während des (ent) packens regelmäßig bestimmte Befehle auszuführen, als eine Art Status.5 Darüber lässt sich Code ausführen und so etwa eine Konsole starten:6
sudo /bin/tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh
Damit sudo sicher ist, sollte man sich daher vor der Freigabe einer Anwendung genauer über deren Möglichkeiten informieren und die ausführbaren Befehle soweit wie möglich einschränken. Im Zweifel hinterfragen bzw. komplexe Anwendungen gar nicht erst freigeben. Manche Dinge sind schlicht nicht abbildbar, wenn man gewisse Verkettungen bedenkt. Darf der Nutzer z.B. auf die Unit-Dateien eines Systemd-Dienstes schreiben, kann er sie verändern und damit indirekt mehr Rechte erhalten. Hier ist auch für das umfangreiche sudo eine Grenze erreicht, bei der nur noch eines hilft: Das Systemd-Unit wird in diesem Beispiel vom Haupt-Administrator (dir) angelegt – nur du hast die Rechte darauf, für Änderungen müssen andere involvierte Personen auf dich zukommen.
In diesem Beispiel völlig unproblematisch, da man Systemd-Units nach dem Anlegen in der Regel nicht mehr anpasst bzw. dies bei Notwendigkeit anderweitig lösen kann, etwa über Startskripte. Nachdem Systemd dieses Skript mit einem im Unit festgelegten eingeschränkten Nutzer startet, lässt sich die Rechteausweitung auf root damit bei sauberer Konfiguration vermeiden.
Protokollierung
Wenn mehrere Nutzer sich (z.B. mit su
) als root anmelden dürfen, ist schwer nachvollziehbar, wer etwas verändert hat. Hier helfen die Audit-Logs von sudo: Sie protokollieren, welcher Nutzer wann einen Befehl als anderer Nutzer ausgeführt hat. Auch blockierte Versuche werden erfasst. Bei regelmäßigen Auswertung lässt sich damit (versuchter) Missbrauch erkennen.
sudo journalctl -f /usr/bin/sudo
May 13 00:12:21 pi5 sudo[12957]: student : TTY=pts/3 ; PWD=/home/student ; USER=root ; COMMAND=/usr/bin/systemctl restart ab apache2
[...]
May 13 00:19:19 pi5 sudo[13018]: student : command not allowed ; TTY=pts/3 ; PWD=/home/student ; USER=root ; COMMAND=/usr/bin/systemctl stop apache2
Was davon brauche ich tatsächlich?
So umfangreich und nützlich die Möglichkeiten von sudo
auch sind – für den PC zuhause, einen Heimserver oder auch gemieteten (virtuellen) Server im Internet hat man in der Regel einen einzigen Administrator. Damit reicht ein kleiner Teil von sudo bereits aus. Vielleicht soll auf einem System noch jemand anders Zugriff haben, weil die Person an bestimmten Projekten mitarbeitet. Hier können weitere Teile sinnvoll sein – etwa dem Nutzer erlauben, einzelne Dienste neu zu starten.
Raspberry Pi Beispiel: GPIO-Ports per Web steuern
Beim Lesen mancher Anleitung könnten Raspberry Pi Nutzer auf eine Idee kommen: GPIO-Ports werden oft als Root-Nutzer angesprochen, beispielsweise mit sudo. Wenn ich diese per Web steuern möchte, muss mein Webserver (bzw. zumindest der PHP-Interpreter) als root laufen. Das ist eine sehr schlechte Idee, da eine Sicherheitslücke in PHP oder meiner Anwendung mit vollen Rechten ausgenutzt werden könnte. Also beschränke ich den dafür üblicherweise eingesetzten Nutzer www-data per sudo, damit er nur auf die GPIO-Pins zugreifen darf.
Ein weiterer Einsatzzweck: Man möchte über die Web-Oberfläche den Raspberry Pi herunterfahren. Hierfür sind Root-Rechte auf /usr/sbin/shutdown
nötig.
Quellen
# pete may change passwords for anyone but root on the hp snakes
pete
HPPA = /usr/bin/passwd ^[a-zA-Z0-9_]+$, !/usr/bin/passwd root
- https://manpages.debian.org/bookworm/manpages-de/su.1.de.html ↩︎
- https://wiki.ubuntuusers.de/sudo/Konfiguration/ ↩︎
- https://www.sudo.ws/posts/2022/03/sudo-1.9.10-using-regular-expressions-in-the-sudoers-file/ ↩︎
- https://gtfobins.github.io/ ↩︎
- https://www.gnu.org/software/tar/manual/html_section/checkpoints.html ↩︎
- https://www.thehacker.recipes/infra/privilege-escalation/unix/sudo ↩︎