このコード挿入が機能しないのはなぜですか?

このコード挿入が機能しないのはなぜですか?
$ touch '"; echo world "'

$ find .  -exec sh -c 'ls -l "$@"' sh {} \;
total 0
-rw-rw-r-- 1 t t 0 Jun  8 23:13 '"; echo world "'
-rw-rw-r-- 1 t t 0 Jun  8 23:13 './"; echo world "'

ファイル名の実行を許可する"$@"ために、ファイル名を開くと閉じる二重引用符がファイル名を開くと閉じる二重引用符とペアになっていないのはなぜですか?echo world

sh引用するには、シェルコマンドの語彙分析中に引用符を認識する必要があるためですか?ここで、ファイル名の引用符は、パラメータ拡張後のシェルコマンドにのみ表示されます。これはすでに語彙分析に合格しており、ファイル名の引用符を認識する時間がありませんか?似ているhttps://unix.stackexchange.com/a/448643/674

違いは、追加してもeval注入が機能しないことです。なぜならeval、シェルがファイル名からおよびを認識しても、"ファイル名もシェルによって削除されるからです。;"

$ find .  -exec sh -c 'eval ls -l "$@"' sh {} \;
total 0
-rw-rw-r-- 1 t t 0 Jun  8 23:13 '"; echo world "'
ls: cannot access './; echo world ': No such file or directory

eval実際に実行される内容を確認するためのデバッグ:

$ find .  -exec sh -c 'echo ls -l "$@"' sh {} \;
ls -l .
ls -l ./"; echo world "

$ ls -l ./"; echo world "
ls: cannot access './; echo world ': No such file or directory

ありがとうございます。

注:コマンド出力に同じファイルの2つのエントリがあるのはなぜですかfind?から。現在のディレクトリへのハードリンクです。 find自体が出力されず、その下のファイルが出力されるのはなぜですか?

ベストアンサー1

ファイル名の開いた二重引用符と閉じる二重引用符がファイル名の開く二重引用符と閉じる二重引用符とペアになっていないのはなぜですか?"$@"

変数拡張は直接のテキスト置換ではないからです。変数内の引用符は引用符として扱われず、現時点では一般的な文字にすぎません。

これは、引用符を含むすべての変数に似ています。

$ foo='"foo  bar"'

引用符はfooコマンドラインの引用符を終了せず、単語の区切りはありません。

$ printf "%s\n" "$foo"
"foo  bar"

そしてここにはいトークン化(拡張が引用されていないため)、引用はfooこれを防ぐためには何もしません。

$ printf "%s\n" $foo
"foo
bar"

後者は、コマンドを変数に保存する簡単なアプローチが機能しない理由と似ています。


の場合、evalなぜ追加したのか分かりませんが、別の拡張が必要な​​ので、そこにコマンド置換を入れることができます。

$ touch '$(uname -m)'
$ find .  -exec sh -c 'eval ls "$@"' sh {} \;
$(uname -m)
ls: cannot access './x86_64': No such file or directory

またはセミコロン:

$ touch ';uname -m'
$ find .  -exec sh -c 'eval ls "$@"' sh {} \;
;uname -m
;uname -m
x86_64

(なぜ2回実行されるのかわかりませんls。)


という名前のファイルでは、"; echo world "引用符が表示されている"$@"場所の一部に展開され、シェル全体が再実行されるため、引用符で囲まれたセミコロンが表示されます。eval

すべての脆弱性の場合、コマンドの注入に使用できる単一のファイル名はなく、コマンドの構成方法によって異なります。

おすすめ記事