Egal wie Sie dies lösen, es wird immer noch nicht viel bewirken. Das hat cdnur Wirkung innerhalb der bash -cSchale.
Kusalananda
Ich gebe nur ein minimales Beispiel für die Frage, es ist keine funktionierende Lösung für mein eigentliches Problem, nämlich unix.stackexchange.com/a/269080/674 plus das in der Befehlszeichenfolge, für die sudo bash -cich eine variable Erweiterung habe Ein Pfadname, der Leerzeichen enthalten kann.
Tim
Antworten:
13
Es gibt kein Wort Spaltung (wie in dem Merkmal , dass Splits Variablen auf nicht notierte Erweiterungen) in diesem Code als $myvarnicht unquoted wird.
Es gibt jedoch eine Sicherheitsanfälligkeit bezüglich Befehlsinjektion, die $myvarerweitert wird, bevor sie an übergeben wird bash. Sein Inhalt wird also als Bash-Code interpretiert!
Leerzeichen dort führen dazu, dass mehrere Argumente übergeben werden cd, nicht aufgrund der Wortaufteilung , sondern weil sie in der Shell-Syntax als mehrere Token analysiert werden. Mit einem Wert von bye;rebootwird das neu gestartet! ¹
Hier möchten Sie:
sudo bash -c 'cd -P -- "$1"' bash "$myvar"
(wo Sie den Inhalt von $myvarals erstes Argument dieses Inline-Skripts übergeben; beachten Sie, wie beide $myvarund $1für ihre jeweilige Shell zitiert wurden, um das Aufteilen von IFS-Wörtern (und das Globbing) zu verhindern).
Oder:
sudo MYVAR="$myvar" bash -c 'cd -P -- "$MYVAR"'
(wo Sie den Inhalt $myvareiner Umgebungsvariablen übergeben).
Natürlich werden Sie nichts Nützliches erreichen, wenn Sie nurcd in diesem Inline-Skript ausgeführt werden (außer zu prüfen, ob dies möglich rootist cd). Vermutlich möchten Sie das Skript cddort und dann dort etwas anderes tun wie:
Wenn die Absicht war , zu verwenden , sudoum die Lage sein , cdin ein Verzeichnis , das Sie sonst keinen Zugang zu, dann das kann nicht wirklich funktionieren.
sudo sh -c 'cd -P -- "$1" && exec bash' sh "$myvar"
startet ein interaktives bashmit seinem aktuellen Verzeichnis in $myvar. Aber diese Shell wird als ausgeführt root.
Du könntest es tun:
sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
Um eine nicht privilegierte Interaktion bashmit dem aktuellen Verzeichnis zu erhalten $myvar, aber wenn Sie überhaupt nicht die Berechtigung hatten, cdin dieses Verzeichnis zu gelangen, können Sie in diesem Verzeichnis nichts tun, selbst wenn es Ihr aktuelles Arbeitsverzeichnis ist.
$ myvar=/var/spool/cron/crontabs
$ sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash-4.4$ ls
ls: cannot open directory '.':Permission denied
Eine Ausnahme wäre, wenn Sie über eine Suchberechtigung für das Verzeichnis selbst verfügen, jedoch nicht für eine der Verzeichniskomponenten seines Pfads:
¹ Genau genommen würde es für Werte $myvarwie $(seq 10)(wörtlich) natürlich zu einer Wortaufteilung kommen, wenn diese Befehlssubstitution durch die bash Shell als erweitert wirdroot
Es gibt neue (Bash 4.4) Zitate, mit denen Sie direkter tun können, was Sie wollen. Abhängig vom größeren Kontext ist die Verwendung einer der anderen Techniken möglicherweise besser, funktioniert jedoch in diesem begrenzten Kontext.
Wenn Sie dem Inhalt von nicht vertrauen können $myvar, besteht der einzig vernünftige Ansatz darin, GNU printfzu verwenden, um eine maskierte Version davon zu erstellen:
ARGUMENT wird in einem Format gedruckt, das als Shell-Eingabe wiederverwendet werden kann, wobei nicht druckbare Zeichen mit der vorgeschlagenen POSIX- $''Syntax vermieden werden .
Siehe meine Antwort für eine tragbare Version davon.
R .. GitHub STOP HELPING ICE
GNU printfwird dort nur auf GNU-Systemen aufgerufen und wenn dies $(printf '%q' "$myvar")in einer Shell ausgeführt wird, in der printfes nicht eingebaut ist. Die meisten Muscheln sind printfheutzutage eingebaut. Nicht alle unterstützen ein %qobwohl und wenn sie dies tun, würden sie etwas in einem Format zitieren, das von der entsprechenden Shell unterstützt wird, was nicht unbedingt das gleiche sein muss wie das, das von verstanden wird bash. Tatsächlich zitiert bashs printfdie Dinge für einige Werte $myvarin einigen Regionen nicht richtig für sich .
Stéphane Chazelas
Mit bash-4.3zumindest, das ist immer noch ein Befehl Injection - Schwachstelle mit myvar=$'\xa3``reboot`\xa3`' in einem zh_HK.big5hkscs zum Beispiel locale.
Stéphane Chazelas
3
Wie andere angemerkt haben, ist Ihr cdBefehl zunächst nutzlos, da er im Kontext einer Shell ausgeführt wird, die sofort beendet wird. Aber im Allgemeinen macht die Frage Sinn. Was Sie brauchen, ist eine Möglichkeit, eine beliebige Zeichenfolge in Shell zu zitieren , damit sie in einem Kontext verwendet werden kann, in dem sie als Zeichenfolge in Shell-Anführungszeichen interpretiert wird. Ich habe ein Beispiel dafür auf meiner Sh-Tricks- Seite:
quote (){ printf %s\\n "$1"| sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/";}
Mit dieser Funktion können Sie dann Folgendes tun:
Was Stéphane Chazelas vorschlägt, ist definitiv der beste Weg, dies zu tun. Ich werde nur eine Antwort geben, wie man mit der Parametererweiterungssyntax sicher zitiert, anstatt einen sedUnterprozess zu verwenden, wie in der Antwort von R ..
Dadurch wird die CD vor Dateien geschützt, die mit einem Bindestrich (-) beginnen oder Links folgen, die zu Problemen führen können.
Dies funktioniert, wenn Sie darauf vertrauen können, dass der String $myvarein Pfad ist.
"Code-Injection" ist jedoch weiterhin möglich, da Sie "einen String ausführen":
Einfache Anführungszeichen funktionieren hier nicht, da Ihre Variable dann nicht erweitert wird. Wenn Sie sicher sind, dass die Variable für Ihren Pfad bereinigt ist, besteht die einfachste Lösung darin, einfach Anführungszeichen um die resultierende Erweiterung hinzuzufügen, sobald sie sich in der neuen Bash-Shell befindet:
Immer noch eine Sicherheitsanfälligkeit $myvar$(reboot)"; reboot; #
bezüglich
1
Die Verwendung sudo bash -c "cd -P -- '$myvar'"würde das Problem auf nur Werte beschränken $myvar , die einfache Anführungszeichen enthalten, die leichter zu bereinigen wären.
cd
nur Wirkung innerhalb derbash -c
Schale.sudo bash -c
ich eine variable Erweiterung habe Ein Pfadname, der Leerzeichen enthalten kann.Antworten:
Es gibt kein Wort Spaltung (wie in dem Merkmal , dass Splits Variablen auf nicht notierte Erweiterungen) in diesem Code als
$myvar
nicht unquoted wird.Es gibt jedoch eine Sicherheitsanfälligkeit bezüglich Befehlsinjektion, die
$myvar
erweitert wird, bevor sie an übergeben wirdbash
. Sein Inhalt wird also als Bash-Code interpretiert!Leerzeichen dort führen dazu, dass mehrere Argumente übergeben werden
cd
, nicht aufgrund der Wortaufteilung , sondern weil sie in der Shell-Syntax als mehrere Token analysiert werden. Mit einem Wert vonbye;reboot
wird das neu gestartet! ¹Hier möchten Sie:
(wo Sie den Inhalt von
$myvar
als erstes Argument dieses Inline-Skripts übergeben; beachten Sie, wie beide$myvar
und$1
für ihre jeweilige Shell zitiert wurden, um das Aufteilen von IFS-Wörtern (und das Globbing) zu verhindern).Oder:
(wo Sie den Inhalt
$myvar
einer Umgebungsvariablen übergeben).Natürlich werden Sie nichts Nützliches erreichen, wenn Sie nur
cd
in diesem Inline-Skript ausgeführt werden (außer zu prüfen, ob dies möglichroot
istcd
). Vermutlich möchten Sie das Skriptcd
dort und dann dort etwas anderes tun wie:Wenn die Absicht war , zu verwenden ,
sudo
um die Lage sein ,cd
in ein Verzeichnis , das Sie sonst keinen Zugang zu, dann das kann nicht wirklich funktionieren.startet ein interaktives
bash
mit seinem aktuellen Verzeichnis in$myvar
. Aber diese Shell wird als ausgeführtroot
.Du könntest es tun:
Um eine nicht privilegierte Interaktion
bash
mit dem aktuellen Verzeichnis zu erhalten$myvar
, aber wenn Sie überhaupt nicht die Berechtigung hatten,cd
in dieses Verzeichnis zu gelangen, können Sie in diesem Verzeichnis nichts tun, selbst wenn es Ihr aktuelles Arbeitsverzeichnis ist.Eine Ausnahme wäre, wenn Sie über eine Suchberechtigung für das Verzeichnis selbst verfügen, jedoch nicht für eine der Verzeichniskomponenten seines Pfads:
¹ Genau genommen würde es für Werte
$myvar
wie$(seq 10)
(wörtlich) natürlich zu einer Wortaufteilung kommen, wenn diese Befehlssubstitution durch diebash
Shell als erweitert wirdroot
quelle
Es gibt neue (Bash 4.4) Zitate, mit denen Sie direkter tun können, was Sie wollen. Abhängig vom größeren Kontext ist die Verwendung einer der anderen Techniken möglicherweise besser, funktioniert jedoch in diesem begrenzten Kontext.
quelle
Wenn Sie dem Inhalt von nicht vertrauen können
$myvar
, besteht der einzig vernünftige Ansatz darin, GNUprintf
zu verwenden, um eine maskierte Version davon zu erstellen:Wie die
printf
Manpage sagt:quelle
printf
wird dort nur auf GNU-Systemen aufgerufen und wenn dies$(printf '%q' "$myvar")
in einer Shell ausgeführt wird, in derprintf
es nicht eingebaut ist. Die meisten Muscheln sindprintf
heutzutage eingebaut. Nicht alle unterstützen ein%q
obwohl und wenn sie dies tun, würden sie etwas in einem Format zitieren, das von der entsprechenden Shell unterstützt wird, was nicht unbedingt das gleiche sein muss wie das, das von verstanden wirdbash
. Tatsächlich zitiertbash
sprintf
die Dinge für einige Werte$myvar
in einigen Regionen nicht richtig für sich .bash-4.3
zumindest, das ist immer noch ein Befehl Injection - Schwachstelle mitmyvar=$'\xa3``reboot`\xa3`'
in einem zh_HK.big5hkscs zum Beispiel locale.Wie andere angemerkt haben, ist Ihr
cd
Befehl zunächst nutzlos, da er im Kontext einer Shell ausgeführt wird, die sofort beendet wird. Aber im Allgemeinen macht die Frage Sinn. Was Sie brauchen, ist eine Möglichkeit, eine beliebige Zeichenfolge in Shell zu zitieren , damit sie in einem Kontext verwendet werden kann, in dem sie als Zeichenfolge in Shell-Anführungszeichen interpretiert wird. Ich habe ein Beispiel dafür auf meiner Sh-Tricks- Seite:Mit dieser Funktion können Sie dann Folgendes tun:
quelle
Was Stéphane Chazelas vorschlägt, ist definitiv der beste Weg, dies zu tun. Ich werde nur eine Antwort geben, wie man mit der Parametererweiterungssyntax sicher zitiert, anstatt einen
sed
Unterprozess zu verwenden, wie in der Antwort von R ..Die Ausgabe dieses Skripts lautet:
quelle
Ja, es gibt Wortspaltung.
Technisch gesehen wird die Befehlszeile beim Bash-Parsen der Zeile aufgeteilt.
Lassen Sie uns zuerst richtig zitieren:
Die einfachste (und unsicherste) Lösung, um den Befehl so auszuführen, wie Sie es meiner Meinung nach wollen, ist:
Lassen Sie uns bestätigen, was passiert (vorausgesetzt
myvar="/path to/my directory"
):Wie Sie sehen können, wurde die Pfadzeichenfolge auf Leerzeichen aufgeteilt. Und:
Ist nicht geteilt.
Der Befehl (wie geschrieben) ist jedoch unsicher. Bessere Verwendung:
Dadurch wird die CD vor Dateien geschützt, die mit einem Bindestrich (-) beginnen oder Links folgen, die zu Problemen führen können.
Dies funktioniert, wenn Sie darauf vertrauen können, dass der String
$myvar
ein Pfad ist."Code-Injection" ist jedoch weiterhin möglich, da Sie "einen String ausführen":
Sie benötigen ein stärkeres Zitat der Zeichenfolge, wie:
Wie Sie oben sehen können, wurde der Wert nicht interpretiert, sondern nur als verwendet
"$1'
.Jetzt können wir sudo (sicher) verwenden:
Wenn es mehrere Argumente gibt, können Sie Folgendes verwenden:
quelle
Einfache Anführungszeichen funktionieren hier nicht, da Ihre Variable dann nicht erweitert wird. Wenn Sie sicher sind, dass die Variable für Ihren Pfad bereinigt ist, besteht die einfachste Lösung darin, einfach Anführungszeichen um die resultierende Erweiterung hinzuzufügen, sobald sie sich in der neuen Bash-Shell befindet:
quelle
$myvar
$(reboot)
"; reboot; #
sudo bash -c "cd -P -- '$myvar'"
würde das Problem auf nur Werte beschränken$myvar
, die einfache Anführungszeichen enthalten, die leichter zu bereinigen wären.