PNG CRC爆破

预备知识

PNG文件格式

  8字节 → PNG文件头

  再往后就是第一个数据块:数据块由4字节的数据域长度,4字节的类型码,指定长度(前面提到的数据域长度,这里IHDR就是0x0D个字节也即13字节)的数据,和4字节的CRC码组成。

  而IHDR的组成为:4字节宽度,4字节高度,1字节位深度,1字节颜色类型,1字节压缩方法,1字节滤波方法,1字节隔行扫描方法。

对什么数据做CRC

 crc就是对类型码数据域进行计算得到的

实际操作

以‘Buuoj 大白’为例

1. 题目提示“是不是屏幕太小了”,打开dabai.png时报错:“解码错误,不支持或无效的文件”所以应该是图片宽高的错误导致校验不通过。该图片宽679,高256,应该要调整高度。

2. 所以我们应当以二进制形式读入该png文件,然后采集下图红框所圈的部分数据,计算其CRC,将结果与后4字节的校验码进行比对。因为调整高度,所以只需对蓝框中的数据进行修改。

3. 代码如下。

 1 import struct
 2 import binascii
 3 from Crypto.Util.number import bytes_to_long
 4 
 5 img = open("dabai.png", "rb").read()
 6 
 7 for i in range(0xFFFF):
 8     stream = img[12:20] + struct.pack('>i', i) + img[24:29]
 9     crc = binascii.crc32(stream)
10     if crc == bytes_to_long(img[29:33]):
11         print(hex(i))

  高度上限应该不是很大, 这里只遍历 0~0xFFFF。此外,因为img[12:20]等输出的结果是bytes, 所以这里需要利用struct对整型数据格式化, 将其打包为字节流。另外格式符i意味着,4字节的整型。

  而且默认是小端输出,需要改成大端输出。大小端输出方式对比如下(以0x100为例):

  以上代码的输出结果为`0x1df`,所以利用winhex将图片高度部分对应的数据改为0001DF即可正常打开该PNG文件。

Reference

1. https://blog.csdn.net/hherima/article/details/45847043?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.edu_weight

2. https://dev.gameres.com/Program/Visual/Other/PNGFormat.htm

3. https://blog.csdn.net/qq_30638831/article/details/80421019

posted @ 2020-07-07 12:21  vict0r  阅读(2729)  评论(0编辑  收藏  举报