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
2. https://dev.gameres.com/Program/Visual/Other/PNGFormat.htm
3. https://blog.csdn.net/qq_30638831/article/details/80421019