misc入门——图片分析
本篇文章以CTFshow为基础,系统研究一下CTF的misc中有关图片分析的题目。
本人有一定的misc基础,不过都是看啥不会学啥,自认为缺少系统的学习,趁着提前放假,速速静下心来慢慢研究,不求多,坚持就行。
图片基础
misc1
题目图片:
好吧,flag就摆在眼前……为了节省时间,电脑QQ截图之后对图片可以转文字,避免了对着打字会打错的情况。
misc2
题目给了一个txt文件,打开一看全是乱码……
1 | 塒NG |
这时我们可以使用16进制编辑器——winhex进行查看,注意到这里开头的89504E47代表着png图片格式开头,意思是这其实是一张图片。
我们将文件拓展名txt改成png,恢复图片,获得flag:
misc3
题目给了一个bpg格式的文件,我们使用软件honeyview可以浏览图片,获得flag。
misc4
本题给了6个txt文件,目测是6个组成flag,统统拖进winhex先看看。
第一个文件以89504E47开头,改成png文件,获得第一节flag。
第二个文件打开看到Adobe和Photoshop之类的字样,先改成png格式试试,结果成功了,获得了第二节flag。
第三个文件打开之后16进制上几乎全是F,看不到啥有用信息,先改成png,也成功了。(这个文件图床加载不出)
第四个文件打开后在右侧的ASCII区看到了GIF字样,就把这个图片改成gif。
第五个文件打开后又看到了Adobe Photoshop之类的,直接改png。(这个文件图床也加载不出)
第六个打开看不到熟悉的东西,那就直接改png吧。
获得了最终的flag。
信息附加
misc5
题目图片:
这肯定不是真正的flag,我们需要寻找隐藏在图片里的flag,拉进winhex:
我们在ASCII区的最后发现了隐藏的flag。
misc6
题目图片:
继续winhex:
我们借助搜索工具,搜索ctf得到了flag的位置。
misc7
题目:
依旧在winhex里直接搜索flag就能找到。
misc8
题目:
这次,我们直接用winhex搜索并没有找到,然而,当我们搜索png文件头89504E47时,惊人的发现居然存在两个文件头:
这么看是在这个图片里面还隐藏着一个图片,我们可以进行手动分离,下面是两种不同的操作:
一种是把第二个的文件头以后全部复制,新建一格空白的文件,全部复制进去,保存可以得到图片。
另一种是直接去掉第二个文件头之前的所有信息,保留后面的信息。
最终,我们得到了隐藏的图片,获得flag。
misc9
题目:
在winhex里搜索flag就直接搜索到,非常简单。
misc10
题目:
这题在winhex里并没有看到什么有用的信息,直接搜索png也搜索不到,猜测可能是其他类型的隐藏图片,这里我们可以尝试使用kali虚拟机将图片拉进去使用binwalk提取出隐藏文件:
分析文件:binwalk 文件名 --run-as=root
分离文件:binwalk -e 文件名 --run-as=root
如果分离成功会在目标文件的目录中生成一个新的文件夹,文件夹中会有分离后的文件。
可见确实存在隐藏文件,打开桌面新生成的文件夹,获取flag。
misc11
简单在winhex查看了一下,确认没有什么可用信息后继续binwalk,binwalk出来有隐藏文件但是打不开,改了改文件发现也是不行。
最后从大佬那里学来了一个程序叫tweakPNG:使用在文件头正常却无法打开文件的情况,在tweakPNG中,按F7可以预览图片。
打开给的misc11文件,可以看到出现了一些信息:
在继续接下来的操作之前,为了进一步学习,我们需要粗略了解一下png文件结构:
先按F7测试一下,现在还是原来的图片。但是发现这个图片有两个图像数据块,我们可以先右键Delete删掉第一个,然后F7预览一下。或者将上面的IDAT数据块下移,让下面的数据块显示出来,还是F7预览。果然,flag出现了:
misc12
winhex找不到,使用刚刚学的tweakpng试试:
居然有这么多的IDAT块,删掉最开始的IDAT,居然还不能预览,算了,继续删。
删了几个之后突然能预览了,flag出现。
misc13
在winhex里找了老半天也没找到,结果说隐藏在这里:
这flag是隔着一个字符分布的,可以把这段字符复制出来写个python程序:
1 | t='ct¹f…s†hªoKw°{!aeS6¥eT446xc%4Ý8ïf«73•9b‚7ºeEb|2Td~1:däeñ6úeõ412fT8ñ329éal}' |
提交了几次都没过……
网上都直接用的十六进制源码转化的:
1 | t='631A74B96685738668AA6F4B77B07B216114655336A5655434343678632534DD38EF66AB37103395391F628237BA6545627C3254647E313A64E465F136FA65F5341E3107321D665438F1333239E9616C7D' |
最后看了一下不知道为什么很多wp上的16进制数都和现在这个不一样,他们的16进制有一个65成了66,他们的提交能通过,现在的不能通过,其他的没什么问题,算了,估计是题目bug了。
misc14
(还是那张图片)
winhex老操作,没有。binwalk一下,发现了有隐藏文件,-e 居然提取不出来。
临时学习了个dd指令,用来分离文件:
dd if=misc14.jpg of=1.png skip=2103 bs=1
if代表输入文件,of代表输出文件,skip代表跳过到多少个块后开始,bs是代表字节为单位的块的大小,参数还有很多,目前先记住这几个就能分出图片了。
这里由于binwalk查看到在2103个块开始还有一个JPEG文件,那就直接skip到2103开始分离。
成功得到flag。
ctfshow{ce520f767fc465b0787cdb936363e694}
misc15
(还是那张图片)
打开winhex一下子就看到了,很快啊(
misc16
(还是那张图片)
winhex找不到,虚拟机binwalk一下,这次分离出来了flag,提交。
misc17
(还是那张图片)
winhex找不到,虚拟机binwalk一下,分离出了一个压缩包,但是里面的东西是坏的,尝试复原一下也不知道怎么搞,这个压缩包拓展名是bz2。
查了一下wp发现这里用了lsb隐写,但是这一个压缩包也不好弄,学了个zsteg,在kali里用下面这个指令下载zsteg:
gem install zsteg
我们可以使用:zsteg 文件名 --all
查看隐藏在文件里的隐藏信息,如果有flag藏在里面就直接会看到,但是这里并没有,但是我们看到了有隐藏数据:
使用这个指令可以提取出隐藏数据到txt:
steg -E “extradata:0” misc17.png > 1.txt
我们得到了txt文件,打开全是乱码,也找不到flag,这个时候再binwalk一次,得到了flag图片。
misc18
(还是那张图片)
这次作者提示很特别:flag在标题、作者、照相机和镜头型号里。
查看文件的属性,找到flag。
ctfshow{325d60c208f728ac17e5f02d4cf5a839}
misc19
(还是那张图片,拓展名为tif)
提示:flag在主机上的文档名里。
用kali的exiftool来查看图片的信息:发现两段flag。
exiftool 文件名
exiftool 文件名 -g
可以让文件信息显示得更整齐一些。
misc20
(还是那张图片)
提示:flag在评论里。
还是exiftool查看一下,看到了所谓的评论:
手动转化一下中文,一开始脑子抽了忘了 易 是啥了……ctfshow{c97964b1aecf06e1d79c21ddad593e42}
misc21
(还是那张图片)
提示:flag在序号里。
用exiftool查看,发现有以下信息,其中序号serial number有一串数字,但是形式不像是flag。
查了一下是用了16进制转字符串。转出来后得到hex(X&Ys),也就是上面的图中的两个x和y分别转16进制然后组合一下就能得到真正的flag了。
1 | k=[3902939465,2371618619,1082452817,2980145261] |
misc22
(还是那张图片)
提示:flag在图片中。
winhex找不到,用exiftool查看,发现了以下信息:
thumbnail在这里是缩略图的意思,这里使用了缩略图隐写。看到这张图片里面存在缩略图,我们可以前面加入 -b 来预览这张图片的源码,但是我们还是需要提取出这张图片。
网上查到提取缩略图的命令:
exiftool -b -ThumbnailImage image.jpg > thumbnail.jpg
对这张图片用一下,能看到新生成的图片隐隐约约能看到flag了:
misc23
(还是那张图片)
提示:flag在时间里。
直接exiftool吧:
可以看到在第一行已经给了提示了,UnixTimestamp百度了一下叫unix时间戳,Unix 时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。
下面给了好几个时间,有来自最近的,有来自未来的,也有来自过去的,这道题应该就是求出这几个时间的时间戳然后转16进制就能得到最终的flag。
计算什么的,交给网站就行了:
经过转换,我们得到了 874865822 2699237688 2156662245 460377706 四个数,接下来转16进制组合就得到flag了:
1 | k=[874865822,2699237688,2156662245,460377706] |
misc41
提示:H4ppy Apr1l F001’s D4y!
愚人节到了,一群笨蛋往南飞,一会儿排成S字,一会儿排成B字。
题目附带的图片显示不出来,用010查看一下,发现图片的内容不像是平时看到的图片所应该有的内容,看了一会倒是发现了一些有意思的东西:
文件结构
misc24
提示:flag在图片上面。
考虑到修改图片的长宽,给的是bmp文件,我们可以先打开详细信息查看现在的长度和宽度:
现在的分辨率是900*150。
为了更简单的找到图片的长宽在16进制编辑器中的位置,我们可以将长宽的十进制转化为16进制然后直接搜索:
在winhex里,按F8会有一个小工具便于10进制和16进制的转换。
这里我们把150转化成16进制是96,然后就在第一行看到了96的数值,我们增大96,比如说增大到F0,保存,看到图片变高,出现flag。
此外,使用软件010editor(另一个常用的十六进制编译器)使用PNG.bt脚本可以直接利用脚本修改一些基本信息(包括长宽等等)。
misc25
提示:flag在图片下面。
依旧是修改长宽,这次给的是png文件,也是一模一样的操作。还是把高位修改成F0就能得到flag。
misc26
提示:flag还是在图片下面,但到底有多下面?
这次我用了010editor用PNGtemplete脚本直接修改长宽,拉到1000,就不信1000不够:
结果我懵逼了,这原来需要求一下真正的高度:
这就得动用网上的脚本了,下面是一个通用的分别爆破长和宽的脚本:
1 | import struct |
如何理解这个脚本?
在png图片中,存在png的CRC检验码,由四位字节49 48 44 52(转字节为b’IHDR’,代表数据块为IHDR,在第一行很好看到)和后面的13位数据块(前四字节是宽,后四字节为高,后五个字节为五个变量值,我们一般用不到)计算得到。
生成图片时,电脑会根据图片原始的长宽生成一个CRC,但是图片的长宽被篡改,现在的CRC和IHDR计算值转化得到的CRC不匹配,我们需要根据题目的CRC求出真正的长和宽复原图片。
我们可以先获得题目中的IHDR和前面的四位字节IHDR,然后转字符串(注意16进制,转字符串后’\x00’代表一个长度),之后遍历爆破组成一个随机的IHDR,然后与题目中的CRC比较,在python里面,我们可以使用zlib库的crc32()函数计算CRC,当我们新生成的IHDR和题目给的CRC相等时,就代表着我们求出了真正的长和宽。
struct.pack(‘>i’,i):> 表示这里用的是网络序(数据是倒着念的),i 表示四字节无符号整数。
打个比方,struct.pack(‘>i’,150)和struct.pack(‘<i’,150)的输出分别是b’\x00\x00\x00\x96’ 和b’\x96\x00\x00\x00’。
当然,由于本题目中我们已知了准确的宽900求高,所以我们可以不用遍历i,减少运算量:
1 | import struct |
得到了606,十六进制25e,和之前的flag拼起来得到真正的flag。
misc27
提示:flag在图片下面
给的尽管是jpg图片,但都是一样的900*150,这次我先搜索150的96进制找到图片的高给改到FF,保存后看到flag。
misc28
提示:flag在图片下面
这次给的是gif图片,但都是一样的900×150,用010直接改高度,但是一开始没有flag,查了一下是忘了考虑gif带多帧的情况,应该每个都改大点,flag可能藏在某个帧里。
misc29
提示:flag在图片下面
还是gif图片,这次有意思的是这个图真的是个动图:
不过也试试同样的方法,我们改每个帧的高度:
发现除了struct LOGICALSCREENDESCRIPTOR里存在一个长宽以外,下面的data数据里的struct IMAGEDESCRIPTOR也都存在一个长宽:
改好之后确实出现了flag,还好这个gif运动比较慢,帧率低到可以截图到flag,如果比较快就得用stegsolve的 frame browser 查看每一帧了:
misc30
提示:正确的宽度是950。
打开文件,看到一张抽风的图片(这种图我之前瞎改图片长宽的时候也出现过……):
按照提示用010直接改就能看到flag。
misc31
提示:高度是正确的,但正确的宽度是多少呢。
依旧是那张抽风的图片,bmp格式。
拿本题来学习一下bmp文件的格式分析:
计算机能以位图(Bitmap,所谓的bmp)和矢量图(vector)来显示图像。
位图又称为点阵图和光栅(shān)图,使用像素(pixel)来描述图像,用Photoshop处理位图。
矢量图用直线和曲线等来描绘图形,通过数学公式计算得到。
区分两种图片的方法:矢量图可以无限放大不失真,位图不能。
BMP文件由4部分组成:
位图文件头(bitmap-file header)
位图信息头(bitmap-informationheader)
颜色表(color table)
颜色点阵数据(bits data)
由于24位真彩色位图没有颜色表,查看本题图片的属性,所以只有1,2,4三个部分。
下面我们来着重看看位图文件头:
红色区为bfType:为bmp文件的标识,像png的89504E47一样,一定是 BM 二字。
橙色区为bfsize:表示整个bmp文件的大小。(注意Windows的数据是倒着念的,橙色框的数据为0x0070F685)
绿色区应该是八个0,没什么用。
粉色区为bfOffBits:位图文件头+位图信息头+调色板的大小。
位图信息头共四十个字节,我们主要关心宽度和高度就行。
颜色点阵的像素按照自下而上,自左向右排序,RGB也是倒着排的,排成B,G,R。
粗略知道这些信息之后,我们就能解出这道题真正的宽度:
我们只要算出bmp像素数,再算下宽度即可。
用010editor查看bitmapinforheader的位置,发现到53字节结束,整个文件最后一个字节是487255,用487255减去不表示像素的前面的文件头和信息头,得到487202,RGB三个字节表示一个像素,用487202除以三得到像素数,由于高度是正确的,我们只要再除以高度就能得到真正的宽度了。(有余数直接约去就可以,后面看样子是多加入了几个字节)
稍微计算一下,得到真正的宽度是1082,修改,得到flag。
misc32
还是一张图片。
提示:高度是正确的,但正确的宽度是多少呢。
这次给的是png图片,还是用之前那个脚本:
1 | import struct |
得到的长宽修改好之后就得到了flag。
misc33
提示:出题人丧心病狂,把高度也改了
给的是png图片,还是得用脚本,这次同时爆破高和宽:
1 | import struct |
得到正确的高和宽,修改得到flag。
misc34
提示:出题人狗急跳墙,把IHDR块的CRC也改了,但我们知道正确宽度肯定大于900
给了一个乱码图片,我们需要修复这张图片,这里需要知道一点:即使crc不对,长宽对了也能正确显示图片。
所以我们可以根据题目的提示,直接试比900大的宽,从中找到一个合适的:
1 | import struct |
这里写了个脚本,把高大于900的一部分图片每个都生成出来,我们能从一堆黑色照片里面找到一个含有flag的图片。
misc35
提示:出题人负隅顽抗,但我们知道正确宽度肯定大于900
题目给的是jpg图片,这题我先按照上次的方法爆破了一次,发现都是空白图片,并没有成功,难道是高度的问题?
我把图片的高度调到600,发现图片上出现了乱码,看来是高度上也做了手脚,现在调整完之后再爆破一遍,在宽度为993开始的几张图片上都出现了flag:
1 | import struct |
注意jpg图片宽高的位置和长度和png的有所不同,可以使用010找好位置之后再改脚本。
misc36
提示:出题人坦白从宽,正确的宽度在920-950之间
这题给的是gif格式的图片,用010的时候注意动图的大小和帧图片的大小的位置不一样,这个图片只有一帧,所以我们先改这一帧的高,发现乱码,接着爆破:
1 | import struct |
misc37
提示:flag在图片里
打开提供的gif图片,发现文字一直在闪看不清,使用stegsolve的Frame Browser功能进行逐帧查看,发现在第9,14,21,31,34帧有flag的几部分,拼接一下就能得到flag。
misc38
提示:flag在图片里
不过,这次给的是png图片,用stegsolve看不到东西,但是我在010里发现这个图片居然有好多帧,这次用honeyview打开,能看到图片动起来了,继续逐帧查看,获得flag。
misc39
提示:flag就像水,忽快忽慢地流
这次给了gif图片,但是居然有287帧……算了,先找一遍,看完了所有的帧,居然没有。看了看大佬的方法才知道这题是利用不同帧之间的间隔时间来隐写,有点逆天。
这题我们可以用kali的identity进行读取间隔,首先先下载:
1 | sudo apt-get install imagemagick |
然后进行提取:
1 | identify -format "%T " misc39.gif > 1.txt |
我们得到了以下文本:
1 | 37 37 36 36 36 37 37 37 37 37 36 37 36 36 37 37 36 36 37 37 36 37 37 37 36 36 37 37 37 37 36 37 36 36 36 37 37 36 37 37 37 37 37 37 37 36 37 37 37 37 37 37 37 36 37 37 36 37 37 36 37 36 37 36 37 37 36 36 37 36 36 37 37 37 36 36 36 36 37 37 36 36 36 37 36 37 37 36 36 37 36 37 37 36 36 37 37 36 37 37 36 36 37 37 36 36 37 37 37 36 36 37 36 37 37 37 36 36 37 36 37 37 36 37 36 37 37 37 36 36 37 37 36 37 37 36 36 36 37 36 36 37 37 36 37 37 37 37 37 36 36 36 37 36 37 37 36 36 37 36 37 36 37 37 36 36 37 36 36 37 37 36 37 37 36 36 37 37 37 36 36 36 37 37 36 36 37 36 36 36 37 37 37 36 36 37 36 37 37 36 37 37 36 36 37 37 36 36 37 37 37 37 36 36 36 36 37 36 37 37 37 36 36 37 37 37 36 36 37 36 37 37 37 36 36 36 37 36 37 37 36 36 36 37 37 37 37 36 36 36 36 37 36 37 37 36 36 36 36 36 37 37 36 37 36 36 36 37 37 36 37 36 37 36 37 37 37 36 36 37 37 37 37 37 37 36 37 |
猜测为二进制,先转为二进制后转字符串:
1 | t='37 37 36 36 36 37 37 37 37 37 36 37 36 36 37 37 36 36 37 37 36 37 37 37 36 36 37 37 37 37 36 37 36 36 36 37 37 36 37 37 37 37 37 37 37 36 37 37 37 37 37 37 37 36 37 37 36 37 37 36 37 36 37 36 37 37 36 36 37 36 36 37 37 37 36 36 36 36 37 37 36 36 36 37 36 37 37 36 36 37 36 37 37 36 36 37 37 36 37 37 36 36 37 37 36 36 37 37 37 36 36 37 36 37 37 37 36 36 37 36 37 37 36 37 36 37 37 37 36 36 37 37 36 37 37 36 36 36 37 36 36 37 37 36 37 37 37 37 37 36 36 36 37 36 37 37 36 36 37 36 37 36 37 37 36 36 37 36 36 37 37 36 37 37 36 36 37 37 37 36 36 36 37 37 36 36 37 36 36 36 37 37 37 36 36 37 36 37 37 36 37 37 36 36 37 37 36 36 37 37 37 37 36 36 36 36 37 36 37 37 37 36 36 37 37 37 36 36 37 36 37 37 37 36 36 36 37 36 37 37 36 36 36 37 37 37 37 36 36 36 36 37 36 37 37 36 36 36 36 36 37 37 36 37 36 36 36 37 37 36 37 36 37 36 37 37 37 36 36 37 37 37 37 37 37 36 37' |
观察代码可以发现每个字母对应7位2进制,约去了第一位0,转化的时候需要注意。
misc40
提示:flag就像歌,有长有短仿佛岁月悠悠
题目给了一个png图片,用honeyview查看发现是个动图,但是identify无法分解png格式的图片,从网上找了一个APNG分离器用来分解。
总共68张图片,分解完后给了每一个图片的帧间隔,图片里没有flag,看来就跟这个帧间隔有关了,好多图片的帧间隔所给的第一个数值都不一样,跟ASCII码很相近,那就转化一下试试:
1 | for i in range(1,69): |
得到的输出里前面有一些乱码可以忽略,flag在后面。
misc42
提示:flag有多长?2cm……不好意思打错了,41位
在010里查看图片,发现有很多的IDAT块,没啥思路的时候我又用了用tweakpng,发现这个IDAT块很像和ASCII码对应:
把这些length值转化成ASCII码:
1 | num=[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] |
有一些多余的数字,忽略即可。
misc43
提示:错误中隐藏着通往正确答案的道路
我们先寻找寻找有什么问题,用tweakpng打开发现好多crc码报错:
1 | is e59387e5, should be 8385f691 |
我猜测flag就藏在这些数字里,我先用我们的flag头来引一下:
1 | from Crypto.Util.number import * |
通过一些查找等方法,我们发现错误的crc码组合起来就含有flag,我们来转化一下:
1 | num='e59387e593a62e63746673686f777b36656232353839666666663565333930666536623837353034646263303839327d' |
misc44
提示:错误中还隐藏着坑
估计还是上一题的方法,尝试提取一下crc信息,结果一下子来了100多个报错,试了一下也发现找不到flag,看来不是这种方法。
看了一下大佬wp,上面使用了一个叫pngdebugger的程序来分析,源码地址:文件png-debugger · GitCode
我们在debug文件夹下使用cmd使用程序,使用指令pngdebugger img.png > 1.txt
来得到文本式的crc反馈信息:
1 | ...... |
总共有两千多行,其中我们能发现这里面有一些crc是ok的,有一些crc是failed的,可以联想到二进制,对其进行转换(去掉我们不需要的除了IDAT的其他模块):
1 | with open("1.txt","r") as f: |
misc45
提示:有时候也需要换一换思维格式
给了一个png图片,题目提到了转换一种格式,BMP格式的图片的数值存储方式和排序和其他的都不太一样,需要将其转化为BMP图片,有一个及其简单的方法是利用Windows自带的画图工具,另存为BMP文件,就会自动改为BMP格式下的图片。
这个BMP图片在binwalk下能分解出flag图片。
misc46
提示:你见过扶乩吗
给了一个gif图片,发现图片内容在不断移动,这题是要用gif每帧的偏移量进行画图,偏移量可以使用identify直接获取:identify misc46.gif > 1.txt
。
1 | misc46.gif[0] GIF 900x150 900x150+0+0 8-bit sRGB 2c 0.000u 0:00.005 |
得到上面的这些帧信息。写个脚本提取一下偏移量画个图即可:
1 | import matplotlib.pyplot as plt |
这里如果不对坐标进行调整的话出来的字符是反向的,我这里进行了60 - int(l2)
操作,可以得到一个合适的图像:
misc47
提示:没见过扶乩,那你知道笔仙吗
给了一个png图片,打开看是空白,放在honeyview里看发现是个动图,APNG。
颜色通道
misc50
提示:有时候视线也要放低一点
图片上全是各种颜色的色块。
既然是颜色通道有关,先打开stegsolve:
大致用法是:先切换不同的颜色通道,查看图片,可能会直接显示在颜色通道的图片上,或者暴露出隐写痕迹。
打开后下面的两个键可以切换色彩通道,随便点点发现在Blue plane 2发现了一个图像:
但是flag并不全,这像是最后一节,继续又在Green Plane 0和Red Plane 1发现了flag: