我想创建一个 shell 脚本来检查以确保目录中表面上看起来是图像文件的所有文件(例如具有典型的图像文件扩展名,如 .jpg、.bmp 等)实际上是图像文件。
我们最近遇到一个问题,黑客能够在目录中生成文件并将其掩码为 .jpg 文件。我想创建一个 shell 脚本来检查目录中的所有文件,以确保它们是真正的 jpg、gif 或 png 文件。
答案1
答案2
作为快速的第一遍,file
命令可以快速检测图像标题:
if file "$FILE" |grep -qE 'image|bitmap'; then
echo "File '$FILE' has the headers of an image"
fi
bitmap
(如果您想识别,则需要第二次交替Windows BMP 文件因为 libmagic 不使用“图像”一词来描述位图图像。)
然而,我们可以file
使用基于 PHP 的假图像进行欺骗布鲁斯·艾迪格的回答:
$ 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识别
这图像魔术师套房设有确认带有 CLI 前端的脚本将返回给定图像的一些元数据。当预期的元数据不存在时,它会失败,因此它非常适合此目的:
$ 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
到遗忘,因为我们只关心它是否能够成功完成,这是由其退出代码捕获的。)
即使这样仍然可以被欺骗
以下示例使用一个简单的 1x1 白色 GIF,并在末尾添加了相同的 PHP 代码。我不了解 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
并且(取决于实现)它可能留下一些证据(图像中的垃圾)。
答案3
按照@Adam Katz 整理的命令,我发现我的系统总是失败,因为-q
用于抑制 grep 输出的选项使其始终给出零的返回码。删除它可以让它正常工作,但这意味着识别命令的输出散布在屏幕上。
我使用的是 GNU bash,版本 5.1.16(1)-release (x86_64-pc-linux-gnu) 和 GNU grep 3.7,默认情况下随 Xubuntu 22.04.1 LTS 一起提供。
我的解决方案的工作方式与 Adams 相同,从测试中运行必要的命令。
[[ ( $(file "$file" | grep -E 'image|bitmap') != "" ) \
&& ( $(identify $file | grep error) -eq 0 ) ]] \
&& echo "File $file appears to be an image" \
|| echo "File $file appears to be a fake"
我希望这对某人有帮助,就像亚当的帖子对我的帮助一样。