png文件的CRC校验

png图片的CRC校验

png的格式

png文件中分为很多个chunk(数据的基本组成单元)

以下是一些常见的chunk

  • IHDR(Image Header):包含图像的基本信息,如宽度、高度、颜色深度等。
  • IDAT(Image Data):包含图像的实际像素数据。由于 PNG 使用 DEFLATE 压缩算法,实际的图像数据被包含在一个或多个 IDAT 块中。
  • PLTE(Palette):如果图像使用调色板,此块包含调色板中的颜色信息。
  • tEXt(Textual Data):包含关于图像的文本信息,如作者、标题等。
  • tIME(Time Stamp): 包含图像的最后修改时间。

每个chunk的格式

例子

以一个png文件的chunk[0]为例(蓝色部分):

image-20231119003131899

  • 前四个字节 00 00 00 0D 代表这个chunk的数据块的长度是13(0D十进制表示)。

  • 随后的 49 48 44 52 是“IHDR”的ascii码表示(见图右),是固定的格式。

  • 紧跟着的就是数据块 00 00 01 F4 00 00 01 A4 08 06 00 00 00

    • 前四个字节代表图片的宽(00 00 01 F4)
    • 紧跟着的四个字节是高(00 00 01 A4)
    • 剩下的五个字节分别指定了整个图片的
      • 颜色通道的位深度
      • 颜色类型
      • 压缩方法
      • 过滤方法
      • 交错方法
  • 紧跟在数据块后面的四个字节是CRC校验码(CB D6 DF 8A)

所以这个chunk[0]的格式就是这样的:

chunk中数据块的长度(4字节)+IHDR固定标识(4字节)+数据块(长度前面指定)+CRC校验码(4字节)

CRC循环冗余校验码

PNG 文件中的每个 chunk 都包含一个 CRC(循环冗余校验)校验码,用于确保 chunk 的数据在传输或存储过程中没有被损坏或篡改。

这里的CRC 校验码是通过将 chunk 的数据(不包括长度字段和标识符)进行 CRC32 算法计算而生成的。计算得到的 CRC 值被附加到 chunk 数据的末尾。

判断图片格式是否被篡改的关键就是这个CRC校验码

在解析 PNG 图像时,读取器会验证每个 chunk 的 CRC 校验码,以确保数据的完整性。

以010Editor这个软件为例,打开png文件时校验码如果出错,那么就会报错

image-20231119005535792

(图片提示chunk校验码有问题)

知识点:

windows系统打开png时,即使CRC校验结果是错的,也会默认忽略这个结果,打开图片。

而linux系统如果遇到CRC校验结果错误,那么是打不开png的。

拓展:改变图片长和宽的隐写

有些ctf题目会通过改变图片的宽和高来隐藏信息,需要使用编辑器修改回原来的宽和高格式才能看见内容。

png图片的长和宽由chunk[0]指定

chunk[0]的数据数据块的前八个字节就是宽(4字节)高(4字节)

image-20231119003131899

在上图里 “001h” 行的0~7列中,前后4个字节就分别对应宽和高(16进制形式)。

通过修改数据块的宽、高部分,可以使图片显示出隐藏起来的内容。

借助CRC校验码暴力破解 还原图片原来的长宽格式

思路:使用CRC32算法去算不同长宽组合的CRC校验码,去碰撞原来的CRC校验码

这里有一个大佬写的脚本,可以爆破图片原来的高(前提是长未被修改):

原链接:https://www.mondayice.com/2019/12/24/ctf%E9%9A%90%E5%86%99png%E4%B8%ADcrc%E6%A3%80%E9%AA%8C%E9%94%99%E8%AF%AF%E7%9A%84%E5%88%86%E6%9E%90/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 # -*- coding: utf-8 -*-
import binascii
import struct

#指定原来的chunk[0]非校验码部分(17字节)
#x49x48x44x52x00x00x01xF4x00x00x01xA4x08x06x00x00x00

#crc32key存放chunk[0]的校验码
crc32key = 0xCBD6DF8A

#碰撞
for i in range(0, 65535):
height = struct.pack('>i', i)
#CRC: CBD6DF8A
data = 'x49x48x44x52x00x00x01xF4' + height + 'x08x06x00x00x00'

crc32result = binascii.crc32(data) & 0xffffffff

#如果该高度生成的crc校验码和chuank[0]的crc匹配,那么说明这就是原图片高度
if crc32result == crc32key:
print ''.join(map(lambda c: "%02X" % ord(c), height))

拓展,其他使用了CRC校验的文件

除了 PNG 文件之外,一些其他文件格式也使用 CRC 校验码来确保数据的完整性。以下是一些可能包含 CRC 校验码的文件格式的示例:

  1. ZIP 文件 (.zip): 压缩文件格式,其中包含的每个文件都可以带有 CRC 校验码,用于确保文件在解压缩时的完整性。
  2. GZIP 文件 (.gz): 一种用于压缩单个文件的格式,通常包含 CRC32 校验码。
  3. TAR 文件 (.tar): 一种文件存档格式,可以包含多个文件,通常与其他压缩格式(如 gzip)结合使用。CRC 校验码有时会用于确保整个存档的完整性。
  4. Ethernet 帧: 在计算机网络中,以太网帧通常包含一个帧检验序列(FCS),它是 CRC32 的一部分,用于检测在网络传输中是否发生了错误。