文章目录
misc 24
hint:flag在图片上面
所以这道题应该是要修改图片的高度。
直接 010 打开,修改 0010h 行 6 列的 96 为 FF 然后再打开图片即可。
计算一下:
文件头字节: 53
文件尾:675053 (最后的 00 00 不算,是 windows 补充的,算到 FF 结尾即可)
总字节数 = (675053 - 53) = 675000
因为一个像素点由 RGB 三个通道组成,一个通道一个字节。
所以原有的像素值 = 675000 / 3 = 225000 px
我们右键图片查看属性:像素点 = 900*150 < 225000
本着宽度不变,高度应该 = 225000 / 900 = 250 px
misc 25
hint:flag在图片下面。
一样的把图片拉高即可
misc 26
用 Tweakpng 打开图片(010 运行模板也可校验)

crc 校验不对,一定是图片宽高,修改高度一看,要求求出原有高度,上脚本
import binascii
import struct
crcbp = open("D:\desktop_in_D\题目附件垃圾桶\misc26.png", "rb").read() # 打开图片
crc32frombp = int(crcbp[29:33].hex(), 16) # 读取图片中的CRC校验值
print(crc32frombp)
for i in range(4000): # 宽度1-4000进行枚举
for j in range(4000): # 高度1-4000进行枚举
data = crcbp[12:16] + \
struct.pack('>i', i) + struct.pack('>i', j) + crcbp[24:29]
crc32 = binascii.crc32(data) & 0xffffffff
# print(crc32)
if (crc32 == crc32frombp): # 计算当图片大小为i:j时的CRC校验值,与图片中的CRC比较,当相同,则图片大小已经确定
print(i, j)
print('hex:', hex(i), hex(j))
exit(0)
misc 27
hint:flag在图片下面
010 打开图片,alt + 4 打开模板,找到宽高位置改高度即可

misc 28
继续修改高度,但是得预览或者 Stegsolve 打开才能看到图片
misc 29
题目提示还是让我们改高度。
打开来是 gif 文件。所以要一帧一帧改高度,然后丢到 Stegsolve 的 Analyse 的 Frame Browser 模块一帧一帧看
misc 30
正如题目提示修改宽度为 950 即可
misc 31
高度正确让我们计算宽度。
(487253-53)/ 3 / 150 = 1082.666666666667
所以宽度改为 1082
misc 32
高度正确计算宽度,因为是 png 所以脚本爆破即可
misc 33
依然爆破
misc 34
hint:出题人狗急跳墙,把IHDR块的CRC也改了,但我们知道正确宽度肯定大于900
文件头的 crc 值被修改,所以 crc 校验已经能通过了(虽然修改了文件宽度)
所以上面的靠 crc 爆破宽高脚本失效。
那我们就直接爆破宽度然后另存为图片看一下哪一张能正常显示
import zlib
import struct
filename = r"D:\desktop_in_D\题目附件垃圾桶\misc34.png"
with open(filename, 'rb') as f:
all_b = f.read()
for i in range(901,1200):
name = str(i) + ".png"
f1 = open(r"D:\desktop_in_D\题目附件垃圾桶\\" + name,"wb")
im = all_b[:16]+struct.pack('>i',i)+all_b[20:]
f1.write(im)
f1.close()

脚本一把梭哈

misc 35
hint:出题人负隅顽抗,但我们知道正确宽度肯定大于900
import zlib
import struct
filename = r"D:\desktop_in_D\题目附件垃圾桶\misc35.jpg"
with open(filename, 'rb') as f:
all_b = f.read()
#w = all_b[159:161]
#h = all_b[157:159]
for i in range(901,1200):
name = str(i) + ".jpg"
f1 = open(r"D:\desktop_in_D\题目附件垃圾桶\\" + name,"wb")
im = all_b[:159]+struct.pack('>h',i)+all_b[161:] # jpg 宽度长度区域两个字节,所以用 >h
f1.write(im)
f1.close()
爆破 jpg 图片的宽度,还要把高度拉高一点看得到,宽度爆破出来是 997
misc 36
hint:出题人坦白从宽,正确的宽度在920-950之间
可以一个一个试,或者上脚本
import zlib
import struct
filename = r"D:\desktop_in_D\题目附件垃圾桶\misc36.gif"
with open(filename, 'rb') as f:
all_b = f.read()
#w = all_b[159:161]
#h = all_b[157:159]
for i in range(920,951):
name = str(i) + ".gif"
f1 = open(r"D:\desktop_in_D\题目附件垃圾桶\\" + name,"wb")
im = all_b[:38]+struct.pack('>h',i)[::-1]+all_b[40:] # gif 宽度长度区域两个字节,所以用 >h
f1.write(im)
f1.close()
misc 37
stegsolve 一帧一帧看即可
misc 38
binwalk 分离一下然后拖到 TweakPng 里面打开,可以发现是 APNG,是 png 的扩展,动图。

所以我们也拖到 stegsolve 里面,但是不行啊,看来这个只能看 gif 图片。
不过我们有了认识了一个新工具,honeyview 。
在第 9,14,21,31,34 帧上面。
ctfshow{2056782cd57b13261dcbbe3d6eecda17}
misc 39
hint:flag就像水,忽快忽慢地流
打开来是一个动图。有 287 帧,一开始看提示我还以为是出题人调节了动图的速度,人眼看不出来,但是一帧一帧看还是没找到。
其实是动图的每一帧间隔时间不同传递信息
下载工具
apt-get install imagemagick
执行命令将每帧的间隔时间导出到 1.txt
identify -format "%T" misc39.gif > 1.txt
打开来发现由一堆 36,37组成。
把 37 转为 1,36 转为 0,然后 flag 41个字符 287 / 41 = 7,所以把 01 字符串分为 41 组,一组 7 个字符,转 ascii ;
str = '3737363636373737373736373636373736363737363737373636373737373637363636373736373737373737373637373737373737363737363737363736373637373636373636373737363636363737363636373637373636373637373636373736373736363737363637373736363736373737363637363737363736373737363637373637373636363736363737363737373737363636373637373636373637363737363637363637373637373636373737363636373736363736363637373736363736373736373736363737363637373737363636363736373737363637373736363736373737363636373637373636363737373736363636373637373636363636373736373636363737363736373637373736363737373737373637'
# 37 替换为1,36替换为0
str = str.replace('37','1')
str = str.replace('36','0')
print(str)
# # 七个字符为一组转化为 ascii 字符
str = [chr(int(str[i:i+7],2)) for i in range(0,len(str),7)]
print(''.join(str))
misc 40
hint:flag就像歌,有长有短仿佛岁月悠悠
APNG 格式的动图,有一帧一帧看不到 flag,binwalk 分离不了 apng。用 APNG Disassembler 分离。

得到一堆 txt,看来是在每一帧图片之间隐藏信息。
打开 txt,都是类似这种格式

用脚本把每个 txt 的 229 位置上的数提取转 ascii 字符
flag=""
for i in range(1,69):
if(i<10):
f = open('D:\desktop_in_D\题目附件垃圾桶/apngframe0'+str(i)+'.txt')
else:
f = open('D:\desktop_in_D\题目附件垃圾桶/apngframe'+str(i)+'.txt')
s = f.read()
flag += chr(int(s.split("/")[0][6:]))
print(flag)
得到 flag
ctfshow{95ca0297dff0f6b1bdaca394a6fcb95b}
misc 42
hint:flag有多长?2cm……不好意思打错了,41位
010 打开发现有很多长短不一的 IDAT 块。
用 TweakPng 打开,发现 idat 长度不一

把长度转为 ascii字符即可
s = [229,152,191,229,152,191,49,99,116,102,115,104,111,119,123,48,55,56,99,98,100,48,102,57,99,56,100,51,102,50,49,53,56,101,55,48,53,50,57,102,56,57,49,51,99,54,53,125]
for i in s:
print(chr(i),end='')
misc 43
hint:错误中隐藏着通往正确答案的道路
我直接 010 打开就找到了,它给我标紫色了。。。。应该非预期了。
010 打开又是一大堆 IDAT, 拖到 TweakPNG 里面直接报错

结合 hint should 前面的字符串应该就和 flag 有关,都收集起来然后 16 进制转字符串即可
misc 44
hint:错误中还隐藏着坑
010 打开 又看到很多 IDAT 块,这次太多了,按照上一步的做法不太现实。
用一个新工具 pngDebugger,作用官方解释是 Read PNG headers, Check CRC
把检测结果导出到 txt 里
PNGDebugger D:\desktop_in_D\题目附件垃圾桶\misc44.png > 1.txt

把 CRC 校验结果 OK 计为 1 , FAILED 记作 0,统计联合起来转为 ascii。
# 二进制转换为字符串 8 位一组
def bin2str(bin_str):
strs = ''
for i in range(0, len(bin_str), 8):
strs += chr(int(bin_str[i:i + 8], 2))
return strs
strs=''
file_name=r'E:\tools\MISC\png-debugger-master\Debug\1.txt'
with open(file_name, "r") as f:
lines = f.readlines()
for line in lines:
if "OK" in line:
strs += '1'
elif "FAILED" in line:
strs += '0'
# strs 转为 ascii
print(bin2str(strs))
但是这样不行啊,统计了一下 01 长度,发现是 346,不能整除 8 就很难受。再看一下题目应该是只要我们统计 IDAT 的校验,所以先把文本中前十行和最后4行 IHDR 和 IEND 的无用数据去掉,这样就变成 344 个 01 了。刚好够整除 8,8位一组转 ascii 码,用我上面那个脚本

misc 45
hint:有时候也需要换一换思维格式
png和bmp像素点的读取方式不一样,结合提示 思维格式,我们把 png 转化为 bmp (感觉题解太扯淡了)
然后 binwalk -e 分离得到 flag.png
misc 46
hint:你见过扶乩吗
用 identify xxx .gif > 1.txt 得到 gif 每一帧信息。
然后提取出每一帧 xy 轴偏移量,最后利用偏移量绘图

from PIL import Image
import matplotlib.pyplot as plt
f=open('D:\desktop_in_D\题目附件垃圾桶\q.txt')
pp=[]
while 1:
c=f.readline()
if c:
s=eval(c.split('+')[1]+','+c.split('+')[2][:2])
pp.append(s)
print(s)
else:
break
img =Image.new('RGB',(400,70),(255,255,255))
for i in pp:
new = Image.new('RGB',(1,1),(0,0,0))
img.paste(new,i)
img.save('1.png')
misc 47
下载附件为一张 png 图片,是 APNG,也有偏移量。
010打开,有 fcTL 块,是帧控制块, 属于 PNG 规范中的辅助块,包含了当前帧的序列号、图像的宽高及水平垂直偏移量,帧播放时长和绘制方式(dispose_op 和 blend_op)等,每一帧都有一个 fcTL 块。
所以需要从十六进制中提取出偏移量的坐标,再通过坐标进行绘图。
misc 48

让我们计算 FF 数量,算 32 组刚好就是 flag
计算每两个有意义块之间的FF的数量再减一,因为这段中的最后一个FF是下一个有意义块的开头,所以这个 最后一个 FF 是特例,不用计算
0 12 11 0 7 10 13 13 9 0 9 13 0 13 6 0 10 9 2 1 0 1 10 8 11 5 12 7 2 2 3 10
再 10 进制转为 16 进制
arr = [0,12 ,11 ,0 ,7, 10 ,13 ,13, 9 ,0 ,9 ,13 ,0, 13 ,6 ,0 ,10 ,9 ,2, 1 ,0 ,1, 10 ,8 ,11, 5 ,12 ,7 ,2 ,2 ,3 ,10]
for i in arr:
print(hex(i)[2:],end='')
得到
0cb07add909d0d60a92101a8b5c7223a
组合一下
ctfshow{0cb07add909d0d60a92101a8b5c7223a}
misc 49
hint:它们一来就是十六种。本题略脑洞,可跳过
查看 FF E0 - FF EF,16种,刚好32个,E 后面那位就是 flag 里的内容

全部组合起来就是 flag :0c618671a153f5da3948fdb2a2238e44
ctfshow{0c618671a153f5da3948fdb2a2238e44}
文章描述了一系列技术挑战,涉及修改图片尺寸、CRC校验、图像格式分析(如APNG和GIF)、像素操作、编码解码和使用工具(如010、TweakPNG、binwalk)寻找隐藏在图片中的旗面信息。
1万+

被折叠的 条评论
为什么被折叠?



