Script para determinar se os arquivos são Imagens

4

Eu gostaria de criar um script de shell que verificará se todos os arquivos em um diretório são arquivos de imagem.

Recentemente, tivemos um problema em que um hacker conseguiu gerar um arquivo em um diretório e mascará-lo como um arquivo .jpg. Eu gostaria de criar um script de shell para verificar todos os arquivos no diretório para ter certeza de que eles são arquivos reais de jpg, gif ou png.

    
por brentwpeterson 10.03.2015 / 21:52

2 respostas

6

Eu acho que você quer ser muito cuidadoso ao usar file em uma circunstância em que você fornece informações completamente não confiáveis. Por exemplo, RHEL 5 file identificará isso:

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

Como "dados de imagem GIF, versão 87a, 15370 x 28735". O interpretador do PHP não tem problemas para executar essa entrada. Essa falta de problemas é a base para " inclusão de arquivos locais " (LFI) problemas.

Em segundo lugar, file (e até strings ) realmente analisa os arquivos de entrada para informar o que você deseja saber. Esses analisadores são complicados e tem problemas .

Vou sugerir o comando identify fora do pacote ImageMagick . Não é enganado pelo meu exemplo simples acima, e ele só analisa arquivos de imagem corretamente, então deve ser menos propenso a falhas de segurança do que file .

    
por 10.03.2015 / 22:23
4

Como um primeiro passo rápido, o comando file pode detectar rapidamente cabeçalhos de imagem:

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

(A segunda alternação para bitmap é necessária se você quiser reconhecer arquivos BMP do Windows , já que a libmagic não usa a palavra "imagem" para descrever imagens de bitmap.)

No entanto , podemos enganar file com a imagem falsa baseada em PHP de Resposta de 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

Usando o Imagemagick, identifique

A suíte ImageMagick tem um identifique o script com um frontend da CLI que retornará alguns metadados em uma determinada imagem. Ele falha quando os metadados esperados não estão presentes, por isso é ideal para essa finalidade:

$ 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

Para uma digitalização mais rápida de uma grande coleção de arquivos, recomendo colocar os dois juntos:

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

(Isso redireciona a saída de identify para o esquecimento, já que apenas nos preocupamos se foi capaz de concluir com sucesso, o que é capturado pelo seu código de saída.)

Mesmo isso ainda pode ser enganado

O exemplo a seguir usa um simples GIF branco 1x1 com o mesmo código PHP adicionado ao final. Eu não sei PHP e não tenho certeza se isso realmente será executado, mas como o PHP é uma linguagem de template que imprime o literal "text" para qualquer coisa fora de sua tag <?php … ?> , eu assumo que isto irá rodar o código como -é com apenas algum lixo antes da carga útil.

$ { 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

Isso também pode ser feito com um comentário GIF para ser totalmente válido como uma imagem:

$ 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

Escolhi o GIF e aproveitei o sistema de comentários, mas apenas concatenar uma carga útil depois de qualquer imagem também deve funcionar para contornar essa técnica de detecção. É apenas mais difícil do que enganar file e (dependendo da implementação) que pode deixar alguma evidência para trás (o lixo da imagem).

    
por 10.03.2015 / 21:57