Ist es möglich, find -exec sh -c sicher zu verwenden?


29

Ich versuche zu verwenden , findum echo 0in einige Dateien, aber anscheinend funktioniert dies nur mit sh -c:

find /proc/sys/net/ipv6 -name accept_ra -exec sh -c 'echo 0 > {}' \;

Bei der Verwendung von sh -cwith find -execfühle ich mich jedoch sehr unwohl, da ich den Verdacht habe, Probleme mit Zitaten zu haben. Ich habe ein bisschen damit herumgespielt und anscheinend war mein Verdacht berechtigt:

  • Mein Testaufbau:

    martin@dogmeat ~ % cd findtest 
    martin@dogmeat ~/findtest % echo one > file\ with\ spaces
    martin@dogmeat ~/findtest % echo two > file\ with\ \'single\ quotes\'
    martin@dogmeat ~/findtest % echo three > file\ with\ \"double\ quotes\"
    martin@dogmeat ~/findtest % ll
    insgesamt 12K
    -rw-rw-r-- 1 martin martin 6 Sep 17 12:01 file with "double quotes"
    -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with 'single quotes'
    -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with spaces
  • Verwenden find -execohne sh -cscheint ohne Probleme zu funktionieren - hier ist keine Angabe erforderlich:

    martin@dogmeat ~ % find findtest -type f -exec cat {} \;
    one
    two
    three
  • Aber wenn ich es benutze, sh -c {}scheint es eine Art Zitat zu erfordern:

    martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c 'cat {}' \;
    cat: findtest/file: No such file or directory
    cat: with: No such file or directory
    cat: spaces: No such file or directory
    cat: findtest/file: No such file or directory
    cat: with: No such file or directory
    cat: single quotes: No such file or directory
    cat: findtest/file: No such file or directory
    cat: with: No such file or directory
    cat: double quotes: No such file or directory
  • Doppelte Anführungszeichen funktionieren, solange kein Dateiname doppelte Anführungszeichen enthält:

    martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c 'cat "{}"' \;
    one
    two
    cat: findtest/file with double: No such file or directory
    cat: quotes: No such file or directory
  • Einfache Anführungszeichen funktionieren, solange kein Dateiname einfache Anführungszeichen enthält:

    martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c "cat '{}'" \;
    one
    cat: findtest/file with single: No such file or directory
    cat: quotes: No such file or directory
    three

Ich habe keine Lösung gefunden, die in allen Fällen funktioniert. Gibt es etwas , das ich mit Blick auf oder verwendet sh -cin von find -execNatur aus unsicher?

Antworten:


40

Niemals {}in den Shell-Code einbetten ! Dies führt zu einer Sicherheitsanfälligkeit durch Befehlsinjektion. Beachten Sie, dass für cat "{}", es ist nicht nur über die "Zeichen, \, `, $sind auch ein Problem (man denke zum Beispiel eine Datei namens ./$(reboot)/accept_ra).

(Übrigens, einige findImplementierungen lassen Sie das nicht zu, und POSIX lässt das Verhalten nicht spezifiziert, wenn {}es nicht für sich in einem Argument für steht. find)

Hier würden Sie die Dateinamen als separate Argumente zu übergeben sh(nicht im Code Argument) und das shInline - Skript (der Code Argument) beziehen sich auf sie Positionsparameter verwenden:

find . -name accept_ra -exec sh -c 'echo 0 > "$1"' sh {} \;

Oder um zu vermeiden, dass eine shDatei pro Datei ausgeführt wird:

find . -name accept_ra -exec sh -c 'for file do
  echo 0 > "$file"; done' sh {} +

Das gleiche gilt für xargs -I{}oder zsh‚s zargs -I{}. Schreibe nicht:

<list.txt xargs -I {} sh -c 'cmd> {}'

Dies wäre eine Sicherheitsanfälligkeit in Bezug auf Befehlsinjektion wie findoben, aber:

<list.txt xargs sh -c 'for file do cmd > "$file"; done' sh

Dies hat auch den Vorteil, dass keine Datei shpro Datei ausgeführt wird und der Fehler auftritt, wenn list.txtkeine Datei enthalten ist.

Mit zsh‚s zargs, dann würden Sie wahrscheinlich wollen eher eine Funktion verwenden , als Aufruf sh -c:

do-it() cmd > $1
zargs ./*.txt -- do-it

Beachten Sie, dass in allen obigen Beispielen die zweite shin die Inline-Skripte eingeht $0. Sie sollten etwas relevant dort verwenden (wie shoder find-sh), nicht Dinge wie _, -, --oder die leere Zeichenkette, da der Wert in $0für die Shell des Fehlermeldungen verwendet wird:

$ find . -name accept_ra -exec sh -c 'echo 0 > "$1"' inline-sh {} \;
inline-sh: ./accept_ra: Permission denied

GNU parallelfunktioniert anders. Mit ihm haben Sie nicht verwenden möchten , sh -cwie parallelausgeführt wird eine Shell bereits und versucht zu ersetzen {}mit dem Argument in die richtige Syntax für die Shell zitiert .

<list.txt PARALLEL_SHELL=sh parallel 'cmd > {}'

das ist zweite shscheint eine Art Platzhalter zu sein, ist es auch , wenn ersetzt arbeitet _beispielsweise - sehr nützlich , wenn Sie bash Interna nennen wollen: find /tmp -name 'fil*' -exec bash -c 'printf "%q\n" "$1"' _ {} \;. Aber weiß jemand, wo dies dokumentiert ist?
Florian Fida

1
@FlorianFida Das erste Argument für die Shell wird $0(normalerweise der Name der Shell. Sie müssen es in diesem Szenario überspringen, damit es nicht zu einem Ihrer normalen Positionsargumente wird. In der Dokumentation wird dies -cerwähnt.
Etan Reisner


1
@phk, das ist nicht argv[0]hier, das ist nur $0das Skript. Die Seite von Sven ist hier ungenau, rund die Shell wird nicht in einen eingeschränkten Modus versetzt, soweit dies erkennbar ist, und der zshModus wird basierend auf nicht geändert $0. (exec -a rksh ksh -c 'cd /')läuft eingeschränkt ksh, aber nicht ksh -c 'cd /' rksh).
Stéphane Chazelas

1
Stéphane, wenn es Ihnen nichts ausmacht, gibt es eine Antwort von Ihnen, die erklärt, warum man {} nicht in den Shell-Code einbettet? Ich habe alle Ihre Antworten durchsucht , konnte aber keine finden, obwohl ich schwören konnte, dass ich einige Dinge gesehen habe, die Sie zu diesem Thema geschrieben haben, aber ich kann mich nicht erinnern, ob es eine Antwort, ein Kommentar im Chat oder auf einer anderen Site wie Compunix war ... Wenn / wenn Sie die Zeit haben, würden Sie auf den „nie einbetten {}“ Teil bewusstseinserweiternde oder denken Sie , wir eine dedizierte Q zB haben sollte „Auswirkungen auf die Sicherheit der Verwendung findmit -exec sh -cund Einbettung {}in die Shell - Code“ ?
don_crissti
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.