2

次のコードを検討してください

<?php
// warning: this code is unsafe and for demonstrational purposes only,
// do not use in a production environment
$filename = $_GET['filename']; 
$extension = 'txt';
$path = '/absolute/path';
$fullFilename = sprintf('%s/%s.%s', $path, $filename, $extension);
echo file_get_contents($fullFilename);

絶対パスを先頭に追加することは、指定されたパスから離れないようにするための適切な手段ではないことは誰もが知っています (少なくとも私はそう願っています) ../。クエリ文字列に 1 つ以上の " " を挿入するだけで、ファイル上の任意のパスに到達できます。システム。

私の質問は次のとおりです。指定された例と同様に、指定さ$_GET['filename']れた拡張子サフィックスもバイパスできるように操作することもできます。つまり、.txt 以外のファイルがエコーされますか? 私は特に../、プレフィックスと同じ方法で追加されたファイル拡張子をバイパスする特定の制御文字について考えています。

いくつかの制御文字 (たとえば、削除の ASCII コード 127) をクエリ文字列に追加したり、 &&|またはを使用して 2 つのファイル名を連結しようとしまし>たが、すべて役に立ちませんでした。

(ちなみに、この質問はシステムを悪用する目的で尋ねられたものではないことに注意してください。これは、最近私の頭に浮かんだ純粋に架空の質問です。)

4

1 に答える 1

2

確かにnullbyte\0(または%00クエリ文字列でテストしたい場合)はfile_get_contents()、文字列にヒットすると文字列の処理を停止します。

そのため、( などの) の場合、エンディング$_GET['filename']は表示されません (エンディングは表示されますが、処理されません)。../../../../../etc/passwd%00your_page.php?filename=../../../../etc/passwd%00file_get_contents().txt

悲しいことに、sprintf文字列を作成するときにヌルバイトを削除しません。他の制御文字についてはわかりませんが、どちらかといえば、ヌルバイトを削除することを常にお勧めします。ただし、より直感的なアプローチは、許可された文字のホワイトリストを作成preg_match()し、入力に対して a を実行することです。

その上で1つ上に行くrealpath()と、構築された文字列でPHPを使用でき、実際にアクセスされているフルパスが決定されます。したがって、/absolute/path/../../../../etc/passwd\0.txtに渡されるrealpath()と が返され/etc/passwdます。その後、返された値に対してさらに検証を行うことができます (拡張子がまだ.txtあるか、指定された/必要なディレクトリ内にあるかなど)。

于 2012-10-04T16:26:01.533 に答える