PHP Imagick重新解释PNG IDAT块

时间:2017-01-08 16:40:45

标签: php imagemagick png zlib imagick

我注意到PHP Imagick在处理PNG时更改了IDAT块。 究竟是怎么做到的?是否有可能创建保持不变的IDAT块?有可能预测Imagick的结果吗?

此问题的背景信息: 我想知道以下代码(PHP文件上传的一部分)是否可以防止在PNG中隐藏PHP代码(例如webshel​​ls):

$image = new Imagick('uploaded_file.png');
$image->stripImage();
$image->writeImage('secure_file.png');

注释被删除,因此绕过此过滤器的唯一方法是将PHP有效负载隐藏在IDAT块中。如here所述,理论上可行,但即使我将CompressionCompressionQuality设置为用于创建PNG的值,Imagick也会以某种方式重新解释此图像数据。我还设法创建了一个PNG,其ZLIB标题由Imagick保持不变,但原始压缩图像数据并没有。我获得相同输入和输出的唯一PNG是之前通过Imagick的那些。我也试图在source code中找到原因,但无法找到它。

我知道其他检查是必要的,以确保上传的文件实际上是PNG等。如果服务器配置正确,PNG中的PHP代码没有问题,但是现在我和#39;我只是对这个问题感兴趣。

2 个答案:

答案 0 :(得分:1)

IDAT块可以变化并且仍然产生相同的图像。遗憾的是,PNG规范迫使IDAT块形成单个连续数据流。这意味着数据可以不同地分组/分块,但是当重新组装成单个流时将是相同的。实际数据是不同的还是只是“分块”改变了?如果是后者,为什么图像是相同的呢? PNG是一种无损压缩类型,剥离元数据甚至解压缩+重新压缩图像不应更改任何像素值。

如果您正在比较压缩数据并期望它们是相同的,那么它可能会有所不同,但仍会产生相同的图像。这是因为FLATE压缩使用迭代过程来查找先前数据中的最佳匹配。您提供的“质量”数字越高,搜索匹配和缩小输出数据大小的次数就越多。使用zlib,9级deflate请求将比默认值花费更长的时间,导致输出数据量略小。

所以,请回答以下问题:

1)您是否尝试比较剥离操作之前/之后的压缩数据,以查看图像是否以某种方式发生了变化?如果是这样,那么查看压缩数据就不是这样做的了。

2)如果要删除元数据而图像文件的任何其他方面都没有变化,那么您需要自己编写工具。在跳过要删除的块时,浏览PNG块并重新组合新文件实际上是微不足道的。

回答我的问题,我会用更多细节更新我的答案......

答案 1 :(得分:0)

  

我想知道以下代码(PHP文件上传的一部分)是否可以防止在PNG中隐藏PHP代码(例如,webshel​​ls)

你永远不需要考虑这一点。如果您担心人们将webhells隐藏在上传到您服务器的文件中,那么您做错了。

例如,通过PHP解析器提供这些文件....这可以调用webshel​​l来攻击服务器。

来自Imagick自述文件:

  

5)永远不要直接通过PHP直接提供用户直接上传的文件,而是通过网络服务器提供,不调用PHP,或者使用readfile在PHP中提供。

readfile不执行该文件,只是将其发送给最终用户而不调用它,因此完全可以防止您似乎关注的攻击类型。