web-dev-qa-db-ja.com

ファイルが画像かどうかを判別するスクリプト

ディレクトリ内のすべてのファイルが画像ファイルであることを確認するシェルスクリプトを作成したいと思います。

最近、ハッカーがディレクトリにファイルを生成し、それを.jpgファイルとしてマスクできるという問題がありました。シェルスクリプトを作成して、ディレクトリ内のすべてのファイルをチェックして、それらが実際のjpg、gif、またはpngファイルであることを確認します。

4
brentwpeterson

完全に信頼できない入力を与える状況でfileを使用する場合は、細心の注意が必要だと思います。たとえば、RHEL 5 fileはこれを識別します。

GIF87a
<?php
echo "Hello from PHP!\n";
?>

「GIF画像データ、バージョン87a、15370 x 28735」として。 PHPインタプリタはその入力を実行するのに問題はありません。この問題の欠如が " ローカルファイルのインクルード "(LFI)の問題の根拠です。

次に、file(さらにはstrings)が実際に入力ファイルを解析して、知りたいことを伝えます。これらの パーサーは複雑です および 問題があります

ImageMagick スイートからidentifyコマンドを提案します。上記の簡単な例ではだまされず、画像ファイルを正しく解析するだけなので、fileよりもセキュリティ上の欠陥が発生しにくいはずです。

6
Bruce Ediger

簡単な最初のパスとして、 file コマンドは画像ヘッダーをすばやく検出できます。

if file "$FILE" |grep -qE 'image|bitmap'; then
  echo "File '$FILE' has the headers of an image"
fi

bitmapの2番目の代替は、認識したい場合に必要です Windows BMP files libmagicはWordの「イメージ」を使用してビットマップイメージを記述しないため。)

ただし、PHPをベースにした偽のイメージでfileをだますことができます Bruce Edigerの回答

$ echo 'GIF87a<?php echo "Hello from PHP!"; ?>' > fake.gif
$ file fake.gif && echo image detected || echo no image detected
fake.gif: GIF image data, version 87a, 16188 x 26736
image detected

Imagemagick識別の使用

ImageMagick スイートには、特定の画像のメタデータを返すCLIフロントエンドを備えた identify スクリプトがあります。予想されるメタデータが存在しない場合は失敗するため、この目的に最適です。

$ identify fake.gif && echo image detected || echo no image detected
identify-im6.q16: negative or zero image size `fake.gif' @ error/gif.c/ReadGIFImage/1402.
no image detected

大量のファイルのスキャンを高速化するには、両方をまとめることをお勧めします。

if file "$FILE" |grep -qE 'image|bitmap' \
&& ! identify "$FILE" >/dev/null 2>&1; then
  echo "File '$FILE' is a fake image!"
fi

(これは、identifyの出力を忘却にリダイレクトします。これは、正常に完了できたかどうかのみが対象であるため、終了コードによってキャプチャされます。)

これでもまだだまされる可能性があります

次の例では、同じPHPコードが最後に追加されたシンプルな1x1の白いGIFを使用しています。わからないPHP実際には実行されますが、PHPは<?php … ?>タグの外側にリテラル「テキスト」を出力するテンプレート言語であるため、指定されたコードをそのまま実行すると想定しています、ペイロードの前にゴミがいくらかあるだけです。

$ { echo 'R0lGODdhAQABAIAAAP///////ywAAAAAAQABAAACAkQBAD'
    echo 's8P3BocCBlY2hvICJIZWxsbyBmcm9tIFBIUCEiOyA/Pgo='
  } | base64 -d > fake2.gif
$ strings fake2.gif
GIF87a
;<?php echo "Hello from PHP!"; ?>
$ file fake2.gif
fake2.gif: GIF image data, version 87a, 1 x 1
$ identify fake2.gif
fake2.gif GIF 1x1 1x1+0+0 8-bit sRGB 2c 68B 0.000u 0:00.000

これは、GIFコメントを使用して画像として完全に有効にすることもできます。

$ hd fake3.gif
00000000  47 49 46 38 39 61 01 00  01 00 80 00 00 ff ff ff  |GIF89a..........|
00000010  ff ff ff 21 fe 20 3c 3f  70 68 70 20 65 63 68 6f  |...!. <?php echo|
00000020  20 22 48 65 6c 6c 6f 20  66 72 6f 6d 20 50 48 50  | "Hello from PHP|
00000030  21 22 3b 20 3f 3e 00 2c  00 00 00 00 01 00 01 00  |!"; ?>.,........|
00000040  00 02 02 44 01 00 3b                              |...D..;|
00000047

私はGIFを選び、そのコメントシステムを利用しましたが、画像の後にペイロードを連結するだけでも、この検出手法をバイパスすることができます。これは、fileをだますことよりも難しく、(実装によっては)might証拠を残す(画像のゴミ)ことがあります。

6
Adam Katz