「find -exec sh -c」を使っても安全ですか?

「find -exec sh -c」を使っても安全ですか?

私はいくつかのファイルでfindtoを使用しようとしましたが、echo 0明らかにこれは以下でのみ動作しますsh -c

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

ただし、sh -cwithを使用すると、find -exec参照に問題があると疑われるため、不安になります。私はそれを少し触れて、明らかに私の疑いは正当でした。

  • 私のテスト設定:

    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
    
  • find -execなしで使用するとsh -c問題なく動作するようです。ここでは引用は必要ありません。

    martin@dogmeat ~ % find findtest -type f -exec cat {} \;
    one
    two
    three
    
  • しかし、次のように使用する場合はsh -c {}一種の参照が必要なようです。

    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
    
  • ファイル名に二重引用符が含まれていない場合は、二重引用符が機能します。

    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
    
  • ファイル名に一重引用符が含まれていない場合、一重引用符は機能します。

    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
    

すべての状況に適用される解決策が見つかりませんでした。私が見落としているか、sh -c本質的にfind -exec安全でないものを使用しているものはありますか?

ベストアンサー1

{}シェルコードを挿入しないでください。これによりコマンドインジェクションの脆弱性が発生します。の場合、文字に関するものだけでなく問題もcat "{}"あります(例えばというファイルを考慮)。"\`$./$(reboot)/accept_ra

(ちなみに、いくつかのfind実装あなたはこのようなことをするようにしません。POSIX脱退アクション指定されていないの引数に{}単独で存在しない場合)find -exec

shここでは、ファイル名を別の引数として(代わりに)渡そうとします。パスワードパラメータ)とshインラインスクリプト(パスワード引数)位置引数を使用して参照してください。

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

またはshファイルごとに1つずつ実行したくない場合は、次のようにします。

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

またはにも同様に適用されますxargs -I{}。書かないでください:zshzargs -I{}

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

これは上記のようにコマンド注入の脆弱性ですが、次のようfindになります。

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

これはまた、ファイルごとに1つずつ実行されるのを回避するだけでなく、含まれているファイルが存在しないsh場合にエラーを回避できるという利点もあります。list.txt

zshs の場合、zargs次を呼び出す代わりに関数を使用できますsh -c

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

zshでループを使用することもできますが、for非常に短いことがあります。

for f (*.txt) cmd > $f

(ただし、最後の失敗以外の失敗は全終了cmd状態には報告されません。)

上記のすべての例では、sh上記の2番目の項目はインラインスクリプトに入ります。などの項目や空の文字列ではなく、関連項目(orなど)を$0使用する必要があります。メッセージ:shfind-sh_---$0

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

GNUはparallel異なる動作をします。それであなたはできますいいえsh -c使いたいparallel{}すでにシェルを実行しており、シェルの正しい構文に引用されたパラメータを置き換えようとしています。

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

実装に応じて、sh他の文字のエンコーディングにはこれらの文字のエンコーディングが含まれます(実際のおよび実際の文字エンコーディングでは、バイト0x5cおよび0x60に制限されます)

おすすめ記事