1.解压得到。
2.拖进010,发现是png
PNG:文件头格式为89 50 4E 47 0D 0A 1A 0A,文件尾格式为49 45 4E 44 AE 42 60 82。
所以将txt文件改成png,即可。
3.
一个bpg图片,要下一个软件打开:Honeyview · 免费图像查看器 · 下载和功能说明
下载后打开这图片就行。
Honeyview
一款图片查看器,文件出现改动的时候可以实时变化,并且宽容性极强,没看见过他打不开的图片
4.
1.txt拖101发现是png文件,2.txt发现是jpg文件,3.txt发现是bmp文件,4.txt是gif文件,5.txt是tif文件,6.txt是webp文件
要学到一些知识
1.BMP(位图):
文件头标识:BM(即 0x42, 0x4D)
2.GIF(图形交换格式):
文件头标识:GIF87a 或 GIF89a(即 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 或 0x47, 0x49, 0x46, 0x38, 0x39, 0x61)
3.JPEG(联合照片专家组):
文件头标识:FF D8(即 0xFF, 0xD8)
4.PNG(便携式网络图形):
文件头标识:89 50 4E 47 0D 0A 1A 0A(即 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)
5.TIFF(标记图像文件格式):
文件头标识(多种):42 49 4D 00、49 49 2A 00、4D 4D 00 2A(即 0x42, 0x49, 0x4D, 0x00 或 0x49, 0x49, 0x2A, 0x00 或 0x4D, 0x4D, 0x00, 0x2A)
6.WebP(Web 图片格式):
文件头标识(多种):52 49 46 46、57 45 42 50(即 0x52, 0x49, 0x46, 0x46 或 0x57, 0x45, 0x42, 0x50)
7.ICO(图标文件格式):
文件头标识:00 00 01 00(即 0x00, 0x00, 0x01, 0x00)
8.PCX(PC 绘图文件格式):
文件头标识:0A(即 0x0A)
9.PSD(Adobe Photoshop 文件格式):
文件头标识:38 42 50 53(即 0x38, 0x42, 0x50, 0x53)
然后有就是刚刚下的软件,太牛了,直接打开。无敌好用
5.
拖进101,然后看到文件尾,看到flag。
6.
ctrl+f搜索ctfshow,找到flag。
7.
跟上面一样的啊。
8.
题目提示要
这要下载foremost,然后创造一个foremost-file存储分离后的文件(其实好像可以不要创造,指定一个新命名的文件夹会自动创造)。
CTF中的神兵利刃-foremost工具之文件分离_foremost分离文件-CSDN博客
分离后,一定要root权限打开那文件夹,不然图片看不了!一定要记得。
9.
这题提示flag在题目块,直接秒。
10.
这里要用binwalk,kali自带。
binwalk -e file --run-as=root
很强啊,比foremost好用。
从这里知道,一般可以用binwalk看图片藏了什么文件(其同时会分离,可以查看分离文件有没有藏flag),若藏了图片就用foremost分离看看。
11.
此题又要用一个软件,Tweakpng是一个用于 Windows 平台的低级 PNG 图像文件操作工具。它允许用户查看和编辑 PNG 文件的元数据,适用于需要深入了解和修改 PNG 文件内部结构的用户,下面这篇文章有,并且还有其它工具。
一、图片隐写[Stegsolve、binwalk、010editor、WaterMark、BlindWaterMark、文件头尾、tweakpng、APNG Disassembler]-CSDN博客
然后删除第一个idat。
打开即可misc11。
12.
这个idta太多了,又要下载一个软件,看下文。工具 PNG Debugger 的安装使用_pngdebugger-CSDN博客
PNG Debugger 可以进行读取 PNG 图片的数据,检测各数据块中的 CRC 是否正确,在 Windows 下使用。
CRC 码是 循环冗余校验码 的简称,是 png 图片中一种的数据, 是目前使用非常广泛的数据校验方式,不仅能校验传递过来的数据正确性,还能筛查出哪一位出现了错误。
比如可用于判断 png 图片的宽和高是否正确。
起始位置就是debug文绝对路径。
看完上面的步骤我们可以将misc12放到test文件里(我是这样,模范上面的文章)
pngdebugger ../test/misc12.png //‘../前有空格’
工具 PNG Debugger 的安装使用_pngdebugger-CSDN博客
这里跑出来都是对的,一个个删,直到出现flag。(最后删了8个)
13.
提示flag再图片末尾,但是没找到,所以看看wp,发现有两种解法。
第一种观察到了ctfshow,但是都隔着一个字符,所以只有隔着字符读就好了。
第二个就是脚本读嘛。
a="631A74B96685738668AA6F4B77B07B216114655336A5655433346578612534DD38EF66AB35103195381F628237BA6545347C3254647E373A64E465F136FA66F5341E3107321D665438F1333239E9616C7D"
r = ''
s=bytes.fromhex(a)
for i in range(0,len(s),2):
r+=chr(s[i])
print(r)
#fromhex函数把一串16进制字符,每两位转换成16进制的对象
14.
dd if=misc14.jpg of=1.jpeg skip=2103 bs=1
15.
直接搜索就好。
16.
提示说flag在图片数据,直接binwalk看看。
17.
binwalk分析得出有一个bzip,但是什么都分离不出来
zsteg工具:用于检测被隐写在png,bmp图片里的数据。
kali下载。
git clone https://github.com/zed-0xff/zsteg
cd zsteg/
gem install zsteg
发现隐藏的数据,位置处于extradata:0;用命令提取出来。
zsteg -E "extradata:0" misc17.png > 1.txt
然后binwalk。
binwalk -e 1.txt --run-as=root
分出来了一个压缩包。
18.
提示:flag在标题、作者、照相机和镜头型号里。
点开属性,都在详细信息里面。照相机和镜头型号往下拉就可以看到。
19.
题目提示:flag在主机上的文档名里。
EXIF信息查看器,用这个查看器(上面的题也可以)查看详细图片属性。
20.
题目提示:flag在评论里。同样刚刚的查看器打开。
由前几个西替爱抚秀,明显是ctfshow的谐音,所以由此读出flag是
ctfshow{c97964b1aecf06e1d79c21ddad593e42}
21.
提示flag在序号里。
这样交肯定是错的,一般flag都是16进制的字符,所以这里需要将x,y的分辨率与定位4段10进制数字转换分别为16进制,依次拼接。
ctfshow{e8a221498d5c073b4084eb51b1a1686d}
脑洞必须大啊。
22.
提示在图片里
binwalk试了没用,101也看不出,看wp。下载新工具:magicexif,开始使用 MagicEXIF 元数据编辑器
magicexif元数据编辑器是一款非常专业的照片magicexif元数据编辑器,该软件可以通过分析照片的元数据以及
编码特征来计算图像可信度,从而判断照片是否被修改,同时还能对相机的快门次数、镜头参数、光圈档位等进行
查看和编辑。
就是一坨,看不清,换方法。
使用工具exiftool ExifTool完全入门指南 kali自带。
可仿造命令
exiftool -ThumbnailImage -b misc22.jpg > 1.jpg
勉强看清楚。
23.
提示在时间,还是用exit
看上面文章执行命令
exiftool a.jpg //读取文件a.jpg的所有元数据
exiftool --ExposureTime misc23.psd //我直接读曝光时间
这里利用在线时间戳转换,然后将时间戳分别转化为16进制,拼接一起即可。
874865822 2699237688 2156662245 460377706 #全部转为16进制
ctfshow{3425649ea0e31938808c0de51b70ce6a}
41.
jpg图片,但是头格式错了,010修改。
图片没信息。binwalk看看。
也没有,怎么办,我想想。不会了,看wp,我直接一句***,脑洞真大,010搜索F001(其实后面想了想,做不出还是没看懂提示,笨蛋排字不就是F001排字嘛),注意换16进制字节。
提取就是
ctfshow{fcbd427caf4a52f1147ab44346cd1cdd}
图片结构
用tweakpng打开发现CRC校验错误(tweakpng只限制了png),说明要改宽高了
修改png,jpg,gif,bmp四种图片文件的宽高
png: 前四位是宽,后四位是高 //第二行改宽高
jpg: 前两位是高,后两位是宽 //jpg图片文件格式为FFC0后3字节接图片宽高
bmp:前四位是宽,后四位是高,但是是倒着写//第二行改宽高
03 B6———>写成B6 03
先打开属性,确定目前宽高数据,再转换成十六进制在010 editor中找
ctfshow-MISC入门_ctfshowmisc入门-CSDN博客
24.
提示:flag在图片上面。那我们就改一下图片高度。
查看属性,提示flag在上面,那么就改高度。文件头占了53字节,文件结尾在675053字节处。又因为每个像素点由三个字节表示,每个字节控制一种颜色,分别为红、绿、蓝三种颜色。所以文件真实像素大小为(675053-53)/3=225000,所以高度=225000/900=250(16进制是FA),其实这种可以直接拉到最大EE,没必要精密计算。
25.
题目提示flag在图片下面。一样的,这次懒得计算。
但是看到了别人的方法,还是再复现一下。
上面讲述了crc,可以判断png宽高是否正确。所以先看看crc对不对,拖进TweakPNG
发现不对,用脚本爆破算,当图片大小为i:j时的CRC校验值,与图片中的CRC比较,当相同,则图片大小已经确定。
import binascii
import struct
crcbp = open("misc25.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)
学到一个脚本。嘿嘿嘿。
26.
题目提示flag在图片下面,那不跟上面一样,脚本爆破
脚本太好用了吧舒服。
27.
提示依旧是下面。这里jpg修改宽高上面讲了。
jpg: 前两位是高,后两位是宽 //jpg图片文件格式为FFC0后3字节接图片宽高
28.
不知道为什么改那就用模板看看。
29.
这个git图片由许多帧合成的,所以需要每帧都改高度。
先用上面的方法将git图片高度改了。再用stegsolve
30.
题目提示正确的宽度是950。bmp图,950=3b6
alt+4也可以改
31.
题目提示:高度是正确的,但正确的宽度是多少呢。先看下此文章
由上面的文章知道前53字节是头文件。文件结尾字节是457255,头文件字节是53.但是注意最后会剩下2字节,而rgb是3字节构造成的。所以计算是可以去除它。
a=(457255-53)/3
a/=150
print(a)
1082.6666666666667 //如果不算最后2位不构成的rgb字节,算出来的就是整数。
这个题目好像不是正确宽度flag就不会出。
32.
题目提示:高度是正确的,但正确的宽度是多少呢
直接脚本爆破。
import binascii
import struct
crcbp = open("misc32.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)
这个代码只能爆破png图片。
33.
依旧是脚本爆破。
34.
题目提示:出题人狗急跳墙,把IHDR块的CRC也改了,但我们知道正确宽度肯定大于900
CRC爆破png图片宽度和高度原理以及python代码_根据crc得出正确高度-CSDN博客
看上面的文章明白了crc正确爆破宽高的原理,现在题目crc不正确,怎么办?自然是换一个脚本爆破。
import zlib
import struct
filename = "misc34.png"
with open(filename, 'rb') as f:
all_b = f.read()
#w = all_b[16:20]
#h = all_b[20:24]
for i in range(901,1200): #界定宽度的范围
name = str(i) + ".png"
f1 = open(name,"wb")
im = all_b[:16]+struct.pack('>i',i)+all_b[20:]
f1.write(im)
f1.close()
35.
jpg图片代码爆破(已知高度爆破宽度)
这里拿到图片,显然宽高都小了,设置高为600(一直加高度,知道可看到字符就开始爆破),再来爆破。
import zlib
import struct
filename = r"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"misc35" + name,"wb")
im = all_b[:159]+struct.pack('>h',i)+all_b[161:]
f1.write(im)
f1.close()
爆破出来宽度是1000.
36.
题目提示出题人坦白从宽,正确的宽度在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()
37.
直接放到stegsolve
拼接即可。
38.
TweakPng 里面打开,发现是有APNG,是 png 的扩展,动图。
使用Honeyview
拿到flag(honeyview可以看许多图片的动图,stegsolve好像只能看git图片)
flag片段分别在第 9,14,21,31,34 帧上面。
39.
287帧没找到flag。这题其实是动图的每一帧间隔时间不同传递信息
apt-get install imagemagick //安装工具
执行命令将每帧的间隔时间导出到 1.txt
identify -format "%T" misc39.gif > 1.txt
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))
然后 flag 41个字符 287 / 41 = 7,所以把 01 字符串分为 41 组,一组 7 个字符,转 ascii ;
杂项入门-图片篇(文件结构)_010修改图片高度-CSDN博客
40.
tweakpng打开发现是apng(png动图)。
APNG
图片分解器(APNG Disassembler)
是一个用来分解APNG
图片的软件,使用这个工具你可以把APNG
动画图片中的每一帧都分解出来,并且把帧导出保存为图片.
打开txt发现:
用脚本把每个 txt 的 229 位置上的数提取转 ascii 字符
flag=""
for i in range(1,69):
if(i<10):
f = open('apngframe0'+str(i)+'.txt')
else:
f = open('apngframe'+str(i)+'.txt')
s = f.read()
flag += chr(int(s.split("/")[0][6:]))
print(flag)
注意讲python脚本与文件放在一个文件夹。
42.
把长度转为 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='')
ctfshow{078cbd0f9c8d3f2158e70529f8913c65}
43.
tk发现crc错误。我们使用 PNG Debugger看看哪些crc错误。
很好,全错,将错误的IDAT
块的crc-code
提取出来,拼接起来转字符串即可得到flag
(从010中也也可以看到idat块)
ctfshow{6eb2589ffff5e390fe6b87504dbc0892}
44.
这个idat块太多了,先提取出来。
把 CRC 校验结果 OK 计为 1 , FAILED 记作 0,统计联合起来转为 ascii。
但是要把文本中前十行和最后4行 IHDR 和 IEND 的无用数据去掉,这样就变成 344 个 01 了。刚好够整除 8,8位一组转 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'D:\桌面\网安必备\png-debugger-master\Debug\misc44.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))
杂项入门-图片篇(文件结构)_010修改图片高度-CSDN博客
ctfshow{cc1af32bf96308fc1263231be783f69e}
45.
hint:有时候也需要换一换思维格式
这里将把 png在线 转化为 bmp,然后 binwalk -e 分离得到 flag.png
ctfshow{057a722a5587979c34966c2436283e70}
这个我是看wp才知道的,为啥要转bmp,咋想到的,我真不理解。
46.
通过identify查看它的偏移量,提取出GIF的详细信息
identify misc46.gif > message.txt
提取它每次偏移的值当做坐标,再作图
import re
import matplotlib.pyplot as plt
from PIL import Image
f = open("misc46", "r")
s = f.read()
# 正则表达式寻找偏移量
data_s = re.findall(r'GIF .*?\+(\d+)\+(\d+)', s, re.DOTALL)
# 将data_s里的坐标从str类型转换成int类型,不然后面的坐标不能识别
data_s = [[int(i) for i in j] for j in data_s]
# 创建一个新的RGB图像,大小为400*70的像素,背景颜色为白色(RGB的值为(255,255,255))
img = Image.new('RGB', (400, 100), (255, 255, 255))
# 创建一个新的RGB图像,大小为1*1的像素,背景颜色为黑色(RGB的值为(0,0,0))
new = Image.new('RGB', (1, 1), (0, 0, 0))
# 循环每次的坐标
for i in data_s:
# 将new(黑色像素点)粘贴到img(白色像素点)上,相当于填充
img.paste(new, i)
# 显示img图像
plt.imshow(img)
# 显示窗口以查看图像
plt.show()
ctfshow{05906b3be8742a13a93898186bc5802f}
说实话,想不到。
47.
tk打开发现是apng,且有偏移量。我们010打开有 fcTL 块,是帧控制块, 属于 PNG 规范中的辅助块,包含了当前帧的序列号、图像的宽高及水平垂直偏移量,帧播放时长和绘制方式(dispose_op 和 blend_op)等,每一帧都有一个 fcTL 块。
所以需要从十六进制中提取出偏移量的坐标,再通过坐标进行绘图。直接上大佬脚本。
import struct # 导入struct模块,用于处理二进制数据
from PIL import Image # 导入PIL库中的Image模块,用于图像处理
import matplotlib.pyplot as plt # 导入matplotlib的pyplot模块,用于绘图
try:
# 尝试打开名为'misc47.png'的文件,并以二进制读取模式读取
f = open('misc47.png', 'rb')
c = f.read() # 读取文件的全部内容到变量c中
# 从c中找到特定的十六进制序列'6663544C00000001',并截取该位置之后的所有内容
c = c[c.index(bytes.fromhex('6663544C00000001')):]
pp = [] # 初始化一个空列表,用于存储解析出来的数据
# 遍历范围从1到1124,步长为2
for i in range(1, 1124, 2):
# 在c中查找特定的模式'6663544C0000'后跟一个无符号短整型i的位置
start = c.index(bytes.fromhex('6663544C0000') + struct.pack('>h', i))
# 截取从start位置开始的30个字节
fc = c[start:start + 30]
# 打印出fc中特定位置的两个字节序列
print(fc[18:20], fc[22:24])
# 解析fc中特定位置的两个字节序列为无符号短整型,并打印出来
print(struct.unpack('>h', fc[18:20]) + struct.unpack('>h', fc[22:24]))
# 将解析出来的整型值添加到列表pp中
pp.append(struct.unpack('>h', fc[18:20]) + struct.unpack('>h', fc[22:24]))
# 创建一个新的白色图像,大小为400x70像素
img = Image.new('RGB', (400, 70), (255, 255, 255))
# 遍历列表pp中的每个元素
for i in pp:
# 创建一个新的黑色单像素图像
new = Image.new('RGB', (1, 1), (0, 0, 0))
# 将单像素图像粘贴到大图像上,位置由i指定
img.paste(new, i)
# 使用matplotlib显示图像
plt.imshow(img)
plt.show()
except FileNotFoundError:
# 如果文件未找到,打印错误信息
print("文件未找到,请检查文件路径是否正确。")
except Exception as e:
# 如果发生其他错误,打印错误信息
print("发生错误:", str(e))
ctfshow{6d51f85b45a0061754a2776a32cf26c4}
48.
hint:附件的第(Di)七(Qi)题(Ti)中有提示
先换文本查看,
查看dpt(题目提示)。
了解到是有一个 DQT 模块,选中模块可以看到是文本中一行内容,是题目的一点提示。
大致意思是计算 FF 的数量并减1
所以我们计算 FF 数量-1,算 32 组刚好就是 flag
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
转16进制0cb07add909d0d60a92101a8b5c7223a
ctfshow{0cb07add909d0d60a92101a8b5c7223a}
49.
这题看不懂一点,直接照着wp做吧。
FF E0 - FF EF,16种,刚好32个,E 后面那位就是 flag 里的内容。将数据流16进制导出在txt。然后用此代码即可。
with open('misc49.txt', 'r') as file: # 打开文件
content = file.read() # 读取文件内容
content = content.replace('\n', '').replace(' ', '') # 去除换行符和空格
content_list = content.split('FFE')[1:] # 以'FFE'为分隔符分割内容,忽略空字符串
result = "" # 初始化结果字符串
for i in content_list: # 遍历处理后的列表
result += i[:1] # 取每个分割后的字符串的第一个字符
# 生成flag字符串,并取前32个字符
flag = "ctfshow{" + result.lower()[:32] + '}'
print(flag) # 打印最终的flag字符串
ctfshow{0c618671a153f5da3948fdb2a2238e44}
50.
拼接即可。
ctfshow{84470883ee1eec2e886436461bf79111}
53.
使用工具Stegsolve
RGB
通道设置都为0
即可得到flag
ctfshow{69830d5a3a3b5006f7b11193e9bc22a2}
54.
这里是竖排的所以需要调整一下参数
ctfshow{b1f8ab24b8ca223d0affbf372ba0e4fa}
55.
图片是倒的,用代码调正,
from PIL import Image
img = Image.open('misc55.png')
img.transpose(Image.FLIP_TOP_BOTTOM).save('out.png')
发现是pk头。
保存bin,然后改成zip压缩包后缀,解压打开即可。
56.
R4、R2、R1、G4、G2、G1
通道有隐写痕迹
ctfshow{1b30c28a5fca6cec5886b1d2cc8b1263}