Aus dem findutils-Handbuch:
Zum Beispiel Konstrukte wie diese beiden Befehle
# risky find -exec sh -c "something {}" \; find -execdir sh -c "something {}" \;
sind sehr gefährlich. Der Grund dafür ist, dass das '{}' zu einem Dateinamen erweitert wird, der ein Semikolon oder andere Sonderzeichen für die Shell enthalten kann. Wenn zum Beispiel jemand die Datei erstellt, können
/tmp/foo; rm -rf $HOME
die beiden obigen Befehle das Ausgangsverzeichnis eines anderen Benutzers löschen.Führen Sie aus diesem Grund keinen Befehl aus, der nicht vertrauenswürdige Daten (z. B. Dateinamen) an Befehle weitergibt, die Argumente als weiter zu interpretierende Befehle interpretieren (z. B. 'sh').
Im Fall der Shell gibt es eine clevere Lösung für dieses Problem:
# safer find -exec sh -c 'something "$@"' sh {} \; find -execdir sh -c 'something "$@"' sh {} \;
Es ist nicht garantiert, dass dieser Ansatz jedes Problem vermeidet, aber er ist viel sicherer, als Daten nach Wahl eines Angreifers in den Text eines Shell-Befehls zu ersetzen.
- Liegt die Ursache des Problems darin,
find -exec sh -c "something {}" \;
dass der Ersatz für{}
nicht in Anführungszeichen gesetzt und daher nicht als einzelne Zeichenfolge behandelt wird? In der Lösung
find -exec sh -c 'something "$@"' sh {} \;
,zuerst
{}
wird ersetzt, aber da{}
nicht zitiert, hat auch nicht"$@"
das gleiche Problem wie der ursprüngliche Befehl? Zum Beispiel"$@"
wird erweitert werden"/tmp/foo;"
,"rm"
,"-rf"
und"$HOME"
?Warum wird
{}
nicht geflüchtet oder zitiert?
- Könnten Sie andere Beispiele nennen (immer noch mit
sh -c
oder ohne, falls zutreffend; mit oder ohne,find
was möglicherweise nicht erforderlich ist), bei denen die gleiche Art von Problem und Lösung zutrifft und die minimale Beispiele sind, damit wir uns auf das Problem und die Lösung mit konzentrieren können? wenig ablenkung wie möglich? Siehe Möglichkeiten, Argumente für einen Befehl bereitzustellen, der von `bash -c` ausgeführt wird
Vielen Dank.
Antworten:
Dies bezieht sich nicht wirklich auf Zitate, sondern auf die Verarbeitung von Argumenten.
Betrachten Sie das riskante Beispiel:
Dies wird durch die Schale analysiert und aufgeteilt in sechs Worte:
find
,-exec
,sh
,-c
,something {}
(ohne Anführungszeichen mehr);
. Es gibt nichts zu erweitern. Die Shell wirdfind
mit diesen sechs Wörtern als Argumente ausgeführt.Wenn
find
Funde etwas zu verarbeiten, sagen wirfoo; rm -rf $HOME
, ersetzt es{}
mitfoo; rm -rf $HOME
und läuftsh
mit den Argumentensh
,-c
undsomething foo; rm -rf $HOME
.sh
Jetzt wird angezeigt-c
, und als Ergebnis wird das Ergebnis analysiertsomething foo; rm -rf $HOME
( das erste nicht optionale Argument ) und ausgeführt.Betrachten Sie nun die sicherere Variante:
Die Schalenläufe
find
mit den Argumentenfind
,-exec
,sh
,-c
,something "$@"
,sh
,{}
,;
.Nun , wenn
find
Fundefoo; rm -rf $HOME
, ersetzt sie{}
wieder, und läuftsh
mit den Argumentensh
,-c
,something "$@"
,sh
,foo; rm -rf $HOME
.sh
sieht-c
und analysiertsomething "$@"
als auszuführenden Befehlsh
undfoo; rm -rf $HOME
als Positionsparameter ( beginnend mit$0
), erweitert sich"$@"
zufoo; rm -rf $HOME
einem einzelnen Wert und wirdsomething
mit dem einzelnen Argument ausgeführtfoo; rm -rf $HOME
.Sie können dies sehen, indem Sie verwenden
printf
. Erstellen Sie ein neues Verzeichnis, geben Sie es ein und führen Sie es ausFühren Sie die erste Variante wie folgt aus
produziert
während die zweite Variante läuft als
produziert
quelle
{}
nicht geflüchtet oder zitiert?;
und{}
) müssen mit einem '\' versehen oder in Anführungszeichen gesetzt werden, um sie vor der Erweiterung durch die Shell zu schützen." Meinst du, dass es für Bash falsch ist?findutils
Handbuch stammt mindestens aus dem Jahr 1996 ... Natürlich schadet es nicht{}
, entweder als'{}'
oder zu zitieren"{}"
, aber es ist nicht notwendig.find some/path -exec sh -c 'something "$@"' {} \;
gibt es tatsächlich drei Ebenen für die Verarbeitung / Übergabe von Argumenten, zwei der Shell-Variante und eine der Basis-Raw-Betriebssystemvarianten.Teil 1:
find
Verwendet nur Textersetzung.Ja, wenn Sie es ohne Anführungszeichen getan haben:
und ein Angreifer konnte eine Datei mit dem Namen erstellen
; echo owned
, die dann ausgeführt wurdewas dazu führen würde, dass die Shell
echo
dann läuftecho owned
.Wenn Sie jedoch Anführungszeichen hinzugefügt haben, kann der Angreifer Ihre Anführungszeichen einfach beenden und anschließend den böswilligen Befehl ausführen, indem er eine Datei mit dem Namen erstellt
'; echo owned
:die in der Schale Lauf zur Folge hätte
echo ''
,echo owned
.(Wenn Sie die doppelten Anführungszeichen gegen einfache Anführungszeichen austauschen, kann der Angreifer auch den anderen Anführungszeichentyp verwenden.)
Teil 2:
In
find -exec sh -c 'something "$@"' sh {} \;
wird das{}
von der Shell zunächst nicht interpretiert, sondern direkt mit ausgeführtexecve
, sodass das Hinzufügen von Shell-Anführungszeichen nicht hilfreich ist.hat keine Auswirkung, da die Shell die doppelten Anführungszeichen entfernt, bevor sie ausgeführt wird
find
.Fügt Anführungszeichen hinzu, die von der Shell nicht speziell behandelt werden. In den meisten Fällen bedeutet dies lediglich, dass der Befehl nicht das tut, was Sie möchten.
Nachdem es zu erweitern
/tmp/foo;
,rm
,-rf
,$HOME
sollte kein Problem sein, denn das sind Argumentesomething
, undsomething
wahrscheinlich nicht behandelt ihre Argumente als Befehle auszuführen.Teil 3:
Ich gehe davon aus, dass ähnliche Überlegungen für alles gelten, was nicht vertrauenswürdige Eingaben entgegennimmt und als (Teil von) einem Befehl ausführt, zum Beispiel
xargs
undparallel
.quelle
xargs
ist nur gefährlich, wenn-I
oder-J
verwendet wird. Im normalen Betrieb werden nur Argumente an das Ende der Liste angehängt, genau wie dies der-exec ... {} +
Fall ist.parallel
Gegensatz dazu wird standardmäßig eine Shell ohne ausdrückliche Aufforderung des Benutzers ausgeführt, wodurch die anfällige Oberfläche vergrößert wird. Dies ist ein Thema, über das viel diskutiert wurde. Eine Erklärung finden Sie unter unix.stackexchange.com/questions/349483/… .) und den enthaltenen Link zu lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html ).parallel
"Empfänger" -Prozess am anderen Ende eines Sockets erzeugt haben, der in der Lage ist, einen direkten Vorgang ohne Shell durchzuführenexecv
. Welches ist genau das, was ich getan hätte, wenn Sie das Tool implementiert hätten. Ein nicht interaktives Programm zu haben, das sich auf der Grundlage des aktuellen Werts von anders verhält,SHELL
ist kaum zu überraschen.execv
anbietet, ist das einfacher und weniger erstaunlich und eine Regel, die sich nicht über Standorte / Laufzeitumgebungen hinweg ändert.In gewissem Sinne kann aber das Zitieren hier nicht helfen . Der Dateiname, der anstelle von ersetzt wird,
{}
kann einen beliebigen enthalten Zeichen , einschließlich Anführungszeichen . Unabhängig von der Art der Anführungszeichen kann der Dateiname dasselbe enthalten und die Anführungszeichen "ausbrechen".Nr.
"$@"
Erweitert die Positionsparameter als separate Wörter und teilt sie nicht weiter auf. Hier{}
ist ein Argument fürfind
sich undfind
übergibt den aktuellen Dateinamen auch als eindeutiges Argument ansh
. Es ist direkt als Variable im Shell-Skript verfügbar und wird nicht als Shell-Befehl selbst verarbeitet.Es muss nicht sein, in den meisten Muscheln. Wenn Sie ausführen
fish
, muss es sein:fish -c 'echo {}'
Druckt eine leere Zeile. Aber es spielt keine Rolle, ob Sie es zitieren, die Shell entfernt nur die Anführungszeichen.Jedes Mal, wenn Sie einen Dateinamen (oder eine andere unkontrollierte Zeichenfolge) so wie er ist in einer Zeichenfolge erweitern, die als eine Art Code betrachtet wird (*) interpretiert wird, besteht die Möglichkeit einer beliebigen Befehlsausführung.
Dies erweitert beispielsweise
$f
direkt den Perl-Code und führt zu Problemen, wenn ein Dateiname ein doppeltes Anführungszeichen enthält. Das Anführungszeichen im Dateinamen beendet das Anführungszeichen im Perl-Code, und der Rest des Dateinamens kann einen beliebigen Perl-Code enthalten:(Der Dateiname muss etwas seltsam sein, da Perl den gesamten Code im Voraus analysiert, bevor er ausgeführt wird. Daher müssen wir einen Analysefehler vermeiden.)
Während dies sicher durch ein Argument geht:
(Es ist nicht sinnvoll, eine andere Shell direkt von einer Shell aus auszuführen, aber wenn Sie dies tun, ist es ähnlich wie die
find -exec sh ...
Fall.)(* Ein Code enthält SQL, daher obligatorisches XKCD: https://xkcd.com/327/ plus Erläuterung: https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables )
quelle
Ihr Anliegen ist genau der Grund, warum GNU Parallel Eingaben anführt:
Dies wird nicht ausgeführt
echo pwned
.Es wird eine Shell ausgeführt, sodass Sie nicht plötzlich eine Überraschung erleben, wenn Sie Ihren Befehl erweitern:
Weitere Informationen zum Thema "Laichen einer Shell" finden Sie unter: https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell
quelle
find . -print0 | xargs -0 printf "Argument: %s\n"
ist genauso sicher (oder besser gesagt, mehr, da-print0
man mit Dateinamen mit Zeilenumbrüchen richtig umgeht); Das parallele Zitieren ist eine Problemumgehung für ein Problem , das überhaupt nicht existiert, wenn keine Shell vorhanden ist.| wc
jedoch den Befehl erweitern, müssen Sie durch die Rahmen springen, um die Sicherheit zu gewährleisten. GNU Parallel ist standardmäßig sicher.foo {} | wc
insh -c 'foo "$1" | wc
sh {} ` konvertiert würde , könnte das anders sein.