È possibile usare `find -exec sh -c` in modo sicuro?


30

Sto cercando di usare findper echo 0in alcuni file, ma a quanto pare questo funziona solo con sh -c:

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

Ma usare sh -ccon find -execmi fa sentire molto a disagio perché sospetto di aver citato problemi. Ci ho provato un po 'e apparentemente i miei sospetti erano giustificati:

  • La mia configurazione di prova:

    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
  • L'uso find -execsenza sh -csembra funzionare senza problemi - non è necessario un preventivo qui:

    martin@dogmeat ~ % find findtest -type f -exec cat {} \;
    one
    two
    three
  • Ma quando sto usando sh -c {}sembra richiedere una sorta di preventivo:

    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
  • Le virgolette doppie funzionano purché nessun nome di file contenga virgolette doppie:

    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
  • Le virgolette singole funzionano purché nessun nome di file contenga virgolette singole:

    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

Non ho trovato una soluzione che funzioni in tutti i casi. C'è qualcosa che mi domina, o sta usando sh -cin find -execintrinsecamente insicuri?

Risposte:


41

Non inserire mai {}nel codice shell! Ciò crea una vulnerabilità all'iniezione di comandi. Si noti che per cat "{}", è non solo sui "personaggi, \, `, $sono anche un problema (si pensi per esempio un file chiamato ./$(reboot)/accept_ra).

(a proposito, alcune findimplementazioni non ti permetteranno di farlo, e POSIX lascia il comportamento non specificato quando {}non è da solo in un argomento a find)

Qui, vorrai passare i nomi dei file come argomenti separati a sh(non nell'argomento del codice ) e lo shscript inline (l' argomento del codice ) per fare riferimento a loro usando parametri posizionali:

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

Oppure, per evitare di eseguirne uno shper file:

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

Lo stesso vale per xargs -I{}o zshs' zargs -I{}. Non scrivere:

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

Quale sarebbe una vulnerabilità nell'iniezione di comandi allo stesso modo di quanto findsopra, ma:

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

Che ha anche il vantaggio di evitare di eseguirne uno shper file e l'errore quando list.txtnon contiene alcun file.

Con zsh's zargs, probabilmente vorrai usare una funzione piuttosto che invocare sh -c:

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

Si noti che in tutti gli esempi precedenti il ​​secondo shsopra va negli script inline $0. Si dovrebbe usare qualcosa di rilevante lì (come sho find-sh), non le cose piace _, -, --o la stringa vuota, come il valore in $0viene utilizzato per i messaggi di errore della shell:

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

GNU parallelfunziona in modo diverso. Con esso, non si desidera utilizzare sh -cpoiché parallelesegue già una shell e tenta di sostituire {}con l'argomento citato nella sintassi corretta per la shell .

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

questo è secondo shsembra essere una sorta di segnaposto, funziona anche se sostituita da _per esempio - molto utile se si desidera chiamare interni bash: find /tmp -name 'fil*' -exec bash -c 'printf "%q\n" "$1"' _ {} \;. Ma qualcuno sa dove questo è documentato?
Florian Fida,

1
@FlorianFida Il primo argomento della shell diventa $0(di solito il nome della shell. È necessario saltarlo in questo scenario in modo che non mangi uno dei normali argomenti posizionali. La documentazione per -cmenzionare questo.
Etan Reisner,


1
@phk, non è argv[0]qui, è solo $0la sceneggiatura. La pagina di Sven è inaccurata qui, a rnon farà entrare la shell in una modalità limitata per quanto ne sa e zshnon cambierà modalità in base a $0. (exec -a rksh ksh -c 'cd /')verrà eseguito un limitato ksh, ma non ksh -c 'cd /' rksh).
Stéphane Chazelas,

1
Stéphane, se non ti dispiace, c'è una tua risposta che spiega "perché non incorporare {} nel codice della shell"? Ho esaminato tutte le tue risposte sotto trovato ma non sono riuscito a trovarne uno, anche se potrei giurare di aver visto alcune cose che avevi scritto su questo argomento ma non riesco a ricordare se fosse una risposta, un commento in chat o su un altro sito come Compunix ... Se / quando si ha il tempo, ti dispiacerebbe espansione sul "{} Mai incorporare" parte o pensi che dovremmo avere un apposito Q ad esempio "implicazioni di sicurezza di utilizzo findcon -exec sh -ce l'incorporamento {}nel codice shell" ?
don_crissti,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.