どうやら、実行中:
perl -n -e 'some perl code' *
または
find . ... -exec perl -n -e '...' {} +
(の-p
代わりに同じ-n
)
または
perl -e 'some code using <>' *
このサイトに投稿されたワンライナーでよく見られるものは、セキュリティに影響します。どうしたんだ?それを避ける方法は?
どうやら、実行中:
perl -n -e 'some perl code' *
または
find . ... -exec perl -n -e '...' {} +
(の-p
代わりに同じ-n
)
または
perl -e 'some code using <>' *
このサイトに投稿されたワンライナーでよく見られるものは、セキュリティに影響します。どうしたんだ?それを避ける方法は?
回答:
まず、多くのユーティリティと同様に、で始まるファイル名に問題があります-
。にいる間:
sh -c 'inline sh script here' other args
他の引数はに渡されinline sh script
ます; perl
同等の、
perl -e 'inline perl script here' other args
他の引数は、インラインスクリプトではなく、最初にperlに追加のオプションがスキャンされます。したがって、たとえば、-eBEGIN{do something evil}
現在のディレクトリにファイルが呼び出されている場合、
perl -ne 'inline perl script here;' *
(の有無にかかわらず-n
)は何か悪いことをします。
他のユーティリティと同様に、そのための回避策は、オプション終了マーカー(--
)を使用することです。
perl -ne 'inline perl script here;' -- *
しかし、それでも、それはまだ危険であり、それは/ <>
によって使用される演算子にかかっています。-n
-p
この問題はperldoc perlop
ドキュメントで説明されています。
その特別な演算子は、入力の1行(1レコード、デフォルトでは行)を読み取るために使用されます。その入力は、各引数から順番に渡され@ARGV
ます。
に:
perl -pe '' a b
-p
while (<>)
コードのループを意味します(ここでは空です)。
<>
最初に開きa
、ファイルが使い果たされるまでレコードを一度に1行ずつ読み取り、次に開きb
ます...
問題は、ファイルを開くために、最初の安全でない形式を使用することですopen
:
open ARGV, "the file as provided"
その形式では、引数が
"> afile"
、afile
書き込みモードで開き、"cmd|"
、実行cmd
して出力を読み取ります。"|cmd"
、の入力への書き込み用に開いたストリームがありますcmd
。したがって、たとえば:
perl -pe '' 'uname|'
呼び出されたファイルの内容uname|
(完全に有効なファイル名btw)ではなく、uname
コマンドの出力を出力します。
実行している場合:
perl -ne 'something' -- *
そして、誰かがrm -rf "$HOME"|
現在のディレクトリに(再び完全に有効なファイル名)というファイルを作成しました(たとえば、そのディレクトリが他の人によってかつて書き込み可能であったか、危険なアーカイブを抽出したか、または危険なコマンドを実行したため、または他のソフトウェアの別の脆弱性が悪用された場合)、あなたは大きな問題に直面しています。その問題を認識することが重要な領域は、公共の場所でファイルを自動的に処理する/tmp
ツール(またはそのようなツールによって呼び出される可能性のあるツール)です。
呼ばれるファイルは> foo
、foo|
、|foo
問題です。しかし、それよりも少ない範囲< foo
でfoo
、先頭または末尾のASCII間隔文字(スペース、タブ、改行、cr ...を含む)と同様に、これらのファイルは処理されないか、間違ったファイルが処理されます。
また、一部のマルチバイト文字セットの一部の文字(ǖ
BIG5-HKSCSなど)がバイト0x7cで終わることに注意してください|
。
$ printf ǖ | iconv -t BIG5-HKSCS | od -tx1 -tc
0000000 88 7c
210 |
0000002
そのため、その文字セットを使用するロケールでは、
perl -pe '' ./nǖ
実行しようとする./n\x88
ようなコマンドをperl
考えていないユーザーのロケールにそのファイル名を解釈しよう!
私の知る限り、perl
システム全体で一度だけの危険なデフォルト動作を変更するためにできることは何もありません。
まず、ファイル名の最初と最後の文字でのみ問題が発生します。だから、一方、perl -ne '' *
またはperl -ne '' *.txt
問題があり、
perl -ne 'some code' ./*.txt
すべての引数は、今で開始されていないため./
、最後に.txt
(そうではない-
、<
、>
、|
...、スペース)。より一般的には、globの前にを付けることをお勧めし./
ます。また、他の多くのユーティリティ-
で呼び出されるファイルや起動するファイルに関する問題も回避します-
(ここでは、オプションの終わり(--
)マーカーが不要になります)。
を使用-T
してtaint
モードをオンにすると、ある程度役立ちます。このような悪意のあるファイルが検出された場合、コマンドは中止されます(ただし>
、|
場合のみ、not <
またはwhitespace)。
そのようなコマンドをインタラクティブに使用する場合、何か危険なことが起こっていることを警告するので便利です。ただし、何らかの自動処理を行う場合は、ファイルを作成するだけで処理を失敗させることができるため、望ましくない場合があります。
名前に関係なく、すべてのファイルを処理する場合はARGV::readonly
perl
、CPAN のモジュールを使用できます(残念ながら、通常はデフォルトではインストールされません)。それは非常に短いモジュールです:
sub import{ # Tom Christiansen in Message-ID: <24692.1217339882@chthon> # reccomends essentially the following: for (@ARGV){ s/^(\s+)/.\/$1/; # leading whitespace preserved s/^/< /; # force open for input $_.=qq/\0/; # trailing whitespace preserved & pipes forbidden }; };
基本的に、" foo|"
例えばに変換することで@ARGVをサニタイズします"< ./ foo|\0"
。
コマンドのBEGIN
ステートメントでも同じことができますperl -n/-p
。
perl -pe 'BEGIN{$_.="\0" for @ARGV} your code here' ./*
ここで./
は、使用されているという前提でそれを単純化します。
その(および副作用ARGV::readonly
)かかわらずはということである$ARGV
にyour code here
示すNUL文字を末尾のこと。
perl
v5.21.5 以降には、特別な処理を行わないことを除いて<<>>
同様に動作する新しい演算子<>
があります。引数はファイル名としてのみ考慮されます。したがって、これらのバージョンでは、次のように記述できます。
perl -e 'while(<<>>){ ...;}' -- *
(忘れてはいけない--
、または使用./*
、それはファイルを上書きしたり、予期しないコマンドを実行しているのを恐れずにいえ)。
-n
/ -p
それでも危険な<>
形式を使用します。また、シンボリックリンクが引き続き追跡されるため、信頼できないディレクトリで使用しても安全であるとは限りません。
@StéphaneChazelasの回答に加えて、-i
コマンドラインオプションを使用する場合、この問題を心配する必要はありません。
$ perl -pe '' 'uname|'
Linux
$ perl -i -pe '' 'uname|'
Can't open uname|: No such file or directory.
-i
オプションをperl
使用する場合、statを使用してファイルのステータスをチェックしてから処理するためです。
$ strace -fe trace=stat perl -pe '' 'uname|'
stat("/home/cuonglm/perl5/lib/perl5/5.20.1/x86_64-linux", 0x7fffd44dff90) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/5.20.1", 0x7fffd44dff90) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/x86_64-linux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
Process 6106 attached
Linux
Process 6105 suspended
Process 6105 resumed
Process 6106 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
$ strace -fe trace=stat perl -i -pe '' 'uname|'
stat("/home/cuonglm/perl5/lib/perl5/5.20.1/x86_64-linux", 0x7fffdbaf2e50) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/5.20.1", 0x7fffdbaf2e50) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/x86_64-linux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("uname|", 0x785f40) = -1 ENOENT (No such file or directory)
Can't open uname|: No such file or directory.
stat
チェックとその直後に行われる効果的なperl処理との間に競合状態はありませんか?
stat
。ファイルを所定の場所で-i
編集するだけなので、実際のファイルパス以外の引数を受け入れることは意味をなさないので-i
、特別な処理は行われません。