Wie übergebe ich Variablen sicher an root-fähige Skripte?

13

Diese Frage ist ganz allgemein und gilt nicht nur für meine Situation, sondern ... Ich habe eine kleine Busybox-Appliance, mit der ein Benutzer ohne Rootberechtigung ein bestimmtes Skript mit Rootberechtigungen ausführen kann. So etwas wie dieses kleine Skript zum Aktivieren von DHCP, bei dem die einzige Variable ( $1), die in der Befehlszeile (!!) gesendet werden kann, der Hostname ist, der gesendet werden soll:

#!/bin/bash
udhcpc -b -i eth0 -h $1

Zum Ausführen von udhcpc ist Root-Zugriff erforderlich. Dazu möchte ich /etc/sudoersdie folgende Zeile ändern :

joe ALL = NOPASSWD: /path/to/enable_dhcp.sh

was "joe" ermöglichen sollte, das Skript mit root-Rechten einfach auszuführen, indem man einfach Folgendes ausführt:

sudo /path/to/enable_dhcp.sh

und nicht nach einem Passwort gefragt zu werden (was ich will, da ich möchte, dass Joe dieses Skript ausführen kann).

Nun, ich weiß (oder glaube zumindest), dass die Verwendung $1eines Skripts, das leicht mit Root-Rechten ausgeführt werden kann, eine SCHRECKLICHE Idee ist, da Sie in dieses Skript injizieren können, was Sie wollen.

Also ... wie geht man am besten damit um? Wie lasse ich Joe mit Root-Rechten tun, was ich will, erlaube ihm, eine Variable einzugeben (oder effektiv wie mit einer Umgebungsvariablen), während er nicht für Injektionsangriffe offen ist?

Russ
quelle

Antworten:

14

Das Ausführen von Shell-Skripten unter sudoist sicher, sofern diese sudoso konfiguriert sind, dass die Umgebung zurückgesetzt wird . Umgekehrt ist sudodas Ausführen eines Shell-Skripts nicht sicher, wenn die Umgebung nicht zurückgesetzt wird, auch wenn die Parameter des Skripts nicht verwendet werden (siehe Zulassen von setuid für Shell-Skripts ). Stellen Sie sicher , dass Sie Defaults env_resetin /etc/sudoersoder dass diese Option ist die Kompilierung-Standard ( sudo sudo -V | grep envsollte enthalten Reset the environment to a default set of variables).

Die Verwendung der Skriptparameter birgt keine besondere Gefahr. $1Wenn es sich um eine Zeichenfolge handelt, müssen Sie lediglich sicherstellen, dass Sie sie als Zeichenfolge verwenden. (Tun Sie dies zum Beispiel nicht eval "$1".) Offensichtlich ist es hier besonders wichtig, keine Annahmen über den Inhalt der Variablen zu treffen und alle Variablensubstitutionen in doppelte Anführungszeichen zu setzen (dh zu schreiben "$1", nicht zu schreiben $1). Beachten Sie, dass das Setzen von doppelten Anführungszeichen um Variablenersetzungen nicht nur für Skripts gilt, die mit Berechtigungen ausgeführt werden. Sie müssen dies die ganze Zeit tun.

Möglicherweise möchten Sie den Parameter weiter validieren, je nachdem, was udhcpcmit etwas geschieht, das nicht wie ein Hostname aussieht. Dies führt beispielsweise eine erste syntaktische Überprüfung durch:

#!/bin/sh
case "$1" in
  *[!:-.0-9A-Za-z]*|-*) echo 1>&2 "Badly formed host name!"; exit 3;;
esac
udhcpc -b -i eth0 -h "$1"
Gilles 'SO - hör auf böse zu sein'
quelle
Andere Dinge, die berücksichtigt werden müssen, können sich auf das Verhalten dieses Befehls auswirken: aktuelles Arbeitsverzeichnis und auf welche Werte stdin, stdout, stderr verweisen, Signalhandler und ulimits. Wenn Sie beispielsweise Core-Dumps zulassen (bei <kbd> Strg - \ </ kbd>), können Sie dem Benutzer erlauben, Wurf / Run / Lock auszuführen, was auf meinem System ein tmpfs mit sehr begrenzter Größe ist und einen DoS zulassen kann.
Stéphane Chazelas
5

Sie sollten die übergebene Eingabe mit einem bekannten guten Muster abgleichen.

Es sieht beispielsweise so aus, als wäre eine IP-Adresse eine gültige Eingabe für Sie. Sie könnten also so etwas verwenden:

if [[ "$1" =~ ^[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9]$ ]]
then
  udhcpc -b -i eth0 -h "$1"
else
  echo "Don't mess with me pork chop."
fi

Beachten Sie, dass reguläre Ausdrücke nicht getestet wurden. Sie sind dafür verantwortlich, dass Ihre reguläre Ausdrücke keine gefährlichen Elemente zulassen.

Bahamat
quelle