本篇文章以CTFshow为基础,系统研究一下CTF的misc中有关图片分析的题目。

本人有一定的misc基础,不过都是看啥不会学啥,自认为缺少系统的学习,趁着提前放假,速速静下心来慢慢研究,不求多,坚持就行。

CTFshow官方网站

图片基础

misc1

题目图片:

好吧,flag就摆在眼前……为了节省时间,电脑QQ截图之后对图片可以转文字,避免了对着打字会打错的情况。

misc2

题目给了一个txt文件,打开一看全是乱码……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
塒NG


IHDR ? ? 喐F6 sRGB ? gAMA 睆
黙 pHYs t t辠x 鮅DATx^磔;r?防qEr0?碬 ;檋疑ばN渳?'R(e?rbi?\尨椌d?阅?$?W藕烕┵ ?$泋砿 @u? ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P┻ !|0Wo迾7蓓龒y9ソ芗肪腙狃??4m呗?&鮬e挣?j@Ι馊绠z陝疳?骖疬癁>泂2吊?嘴栗bn逕毥]5?O櫨U禠厄sh{oF熺^n帖嗑侵僞骨?蘸t炜k|=?4雧?-e峞v曤唏槞?慜胚?XT跶16#N?V-mr?垘??cй?踀z轣o潭-~t患?黰Y献雥斁?髹薔濐锻u邮佅?Qc曡[ニ訳z??涰惮QN灟窙嗑茼?I蛂?蕌yt豞n?攕lQ%i蛀DmZ?塑Q?穗C诌Z?荬洽軒j眣艖部'囂/??
你A癊姣邬谬e??/.?!t+?瓒aK佐 ain ??'塎蠿{朆橿薹M\滠?踍卉C鷢n?撓N贐2'X汋?>酞齵?O6)誐折Q)6/Ff,雥驋零朣v窟?Q
?杜幜m澑;|N=oBxh€??l^<?
Z+ e渢倎+蝙鉆飉瑧}K 眄/r )戌茯匎︼伟v箛??鵚黚[曝Y2?撶途犧?酞?x滯~B蒞Xv鈩鴫韛 }瓺l^挏82F主t翲鲒据sa?振?v嬜鹴鶅?瀯p訿uL瞬挻2仸L;岃[jejh禧u ?Z弈-Y 髂???筴誶???y載呓x9?途犧?蘻廇摄骲l喵M?j矗bl^挏82F主歹)i犹钧jI?眈?n??e}棸/?/檁?罴{k?内紭:嵐瘮s篦g髏V3ㄌ砼??芊摔革驿e钝[#僬彭絠N6'w??殈郭踻?庚瀤y/蘭3i蝴殈V箇??u]薹駳碣4'荜i蛀dmZ?薼)湛綴1ī鬁
歡熖?囶套_t≌広?)M}娳籼|赬輄26?Y笋蝮籡w帺竢无?耵痽>?卽?y'磇h朓m?锋馭违?螫=??俫?篌??玮?鵾鷑~莆j?A籐砩t4囐屋贄D侈椮销?咡脋库?>鮋帩8趑<蓮Z;*莊攕鲅黣e効?J醍1荴貘蒜彥呬儍?bE?;r?睳?4舜=?C吔?v|櫘?3邠鵡p?*髂焊m&蓮倱)D4鸜煿爽涌?昇覝8储銰詭
屚槢?"耒?輁尒?!膠<??躇脬?e?-靫璆???>q鲴/?檼W %鍨?薚蛕_c沄?7蓮ZvZO?i?苀H?o5N?~泷g?輼??#epB璁?贐
2>槴钸|鑆b屿熛;?l??媃炢?浕鲧趍琚褍Vr碋雃艟漽p6崖炤呥跰X&痪剫?遀爅澚'x堀坐綰綥'汒猊麅掀焕犍遪
n岃g…撤?疌籇很邈媱?х拈?鰳﨨籃篺?叻b谨Xc檣箍ナ崮¨KE!]抳?6缤{LGf廤掀n甈R敌l?搕緒顒n?s翙鸧fBx陘巛?蟆=€筄
濻贊|翡0€u濩瓧←~?缰璱譳R潽鲖??唏肟?eWm蹳3jw鹕?檠,域幏Ba?杁\?7鯯O鍉31x"Qez?艝沅"7?/ 箵昗O骟y&?h謠鼍5隴h峞啹?蛥鐘S艖吥珬洴著?/?鏣b襮~\41,yw鮴 烬N71?劵KsRX贴 踌O?为糨癶杋k;Υ^v麔v悎萆8瑴?yF坶舡6紊G鬧?蜺<.猋ε痙B!躬sf湩?3也?e菢6?XN\躉祿B蛕羡穎剿?c頷箇7DM?i?cs峁釺qd1癃IJ?^缗yZs?莀nL?咵b覌郭陧+#町?!那癘 章闢耏k甯m俴疁諦壆?f崢??鳇祎毱
畄rZ?ca伤伪助p~旷掦?踂鬓G画N趴胇?Y赝j鉽薥?穙i杋娿歪苺P莞鯒?椲猒DR町禅2@n檪躸烔c娤鞧醹?牽熒cR`姜螙un鑃ま#馋璚颵]?颯猞v?靡?其#I;N涊?娥8>酴佝#媹Wn禌搞63檅?B}-赭伩}^8Op宓綗衝聖S?謖蒜?! t I0i
??gd4荏鮡床脥佑?=?躝霡;?擴輥劫n:僜^堑藴讧]锴}JO事蒁f咭,??鎫o ?wle~<@X町懬衞@檪荦 i竺?膕/睽 ?飠c| 鎵>'VCr鳝T颵朸鎞+僤吴}g阺伩碣术?a;N?sI?c?缚┾仍?饈? >e侗荭秋擌霚鵎硶?L7峭慸懔缯藂胼A`l鮹脐2沩M?~?OqSV犔祠?[B?晹啕\?讖7HBA泡ⅲt髯 帖?$*要骉 p蕸j?坫?&埃鶹?Mr糂n邖銮铁s

?鈘w??兪?帲罘租飛NH塹砥\q&Y秒荲}蜘??笕庛f?F禰挫柜j?q;N?忹埄馊漶*?韒`矑倨鰍瀋(?鱫EM6&锇 O.輖篡瞳訛9烏鞑鵣:!?0埃簙珓PX'n筩'7萪濦$'IpoYQ穕裷賰%斩v9阴?擞g%歉遺趈T?[嶹"???剀c5V噹L>恊湄稌Hs縪?脽悿鈬X褄wh顊GWQ骜?荄v?uf+Sr谘冶y愿?幪疪輗鸁贿?譃c◢?黠舥T桠?杛蜵~濅]竪髾魒;?笊勑-|蝸'崹P??ぷ C;羴?q`昡Up\见#蒨湛祧彖C?;?+^=鷣w垮\!賝删栒??疡鲴鲎簖趽┸rwe鮼 c?漩憸壧0?"T鐚睙?蛚wH闿l5e.涌蒹i叨咕房w鋦?*描皰蹘时刽笣*嶭?2斌景锘}"倨犹14茻[?]?O墭?圮瞘?2莙铟%?昃蕏崑.簨獨纥M狗鬑w鮛?饩-l纊?oxr枱/4踼+賟賵
箸?盟O貗?枦8糬讂嬛孚<x嵵妪矩殪搚lFo子鏾猳2?哟躯`疁7_鮺?鯴浥€r玔b檮幆胣6?s喩^缦]`{蛕Wn犹z梇c櫱垢輾fRt磃bk?9'躻oG縴??柾葑?薈 hG遑\z?UYV?3?蹧4掀畈S紒ye?4茻輋c?按U悻棆嶾{p?羨莙蟍X?=诒g?A<I$剼濸觼 t然??巖^
=ㄎ%ku籉h鶋顁漞#?;%捴`,7qy?狼?vn捜/扏喈?$i杋钽m&螝>m癡y鮱噞r?O褂朮泮[铈L<?\?F侈
罨H終蘣磽㈨611郊啐飶粰皗.汊说=懰\荦d瀤拵庭鐘S艖%奴?1魮炉E牄n嶲vmvX薘笉絇e唣h?r}溶
C桇h擈沓" `淐?駩1k/?堚B?vFh堀?藈飩Zw\轿h/t*箋篕踢鏮-暞欍$縼c-E矻?o粻?嶝 隠V鹗=9,w1K,搈穾STn樘uQ侈遂[忿]k,sy菈┓u?wm禦沦G髼3?憓-篳?浀鐘S艖%蒴h捖霫|鳬畆寸e七測蓩軯 G軡溛肬硡脘
盈鼙3簭n滌|?掰泀躖gb?肽鏈袁E?憙??絵?驨m螘曨]椭??=歟氭x?嚦狆褰|?fA阪粐_eYnK,摥=QX弉{.蛚缒彎GK笀╕飁鯹巨S諼?=蹤8朁橪驸顬戫8[lb?拆?頔勑揬-bN??x尶?噫謂某51媳'
狪弙稯蹞V魧辙俕容铝彆H8彇摭8%螺奈{F?眜蓷頨g賘锂m鼷? ?歟氥x 噓醍椾q?玟渜w||顾[b?W捭3磔嗐剘枯f烉$繐芝Y顴霏R飍k,鬁瑂X崮gLL邘竽鎍#笄?覗8шn涃Ⅱ都逴w煔k蛇R恠 5=?殏槕H??父=t
鱕碇擓?飵U%贶疥;檹皱вwu e?雚幼D晤|捛??鎶T鰏?歟汑x? 迺れ壌{藊\?t聴9?wYK,擁跑X繉o媥?GI藶溲2麨髦X鎦?úw 嘅F篖;j苀砉釺qd趚5峰桐唽恳}-掐9攽??j#5Oz鵬礻?p"!?H璀掚wx硴{前鐜晭A
迚Ae'd泅?嗜-{雚鱼€?⒙[c,)?甇c焾
\矻?醜傒惙径爝κO2迯?莲d筀Yb?螇Bvrs
?6i.X锱霏V锞5杫v?ae? 竨";曥讂惫鬨q?2_紥Q~Twis*养+0G噱鎘珑P??o櫀泟? 捒q稈G亠搹尯D鸊壶廛)滉蕛铜筌譙gM瑵g詗碹? D^<唁c?鰰鹏鄍~葇鱑鳻痵eP??请=c轓8z啁氞瀌D薧8W莲x?Xb橠$wc菽 聖 )霚峋襕H侈U鄞`絯腆s顒6uV?€梄鳠#嫹l.=W?幪?S鶴?桐溷蠜#缈??数?o?榦謘?勘?箣]x骮?℡媜婀,8?xQL锽粇潒棵[4?酠鹸.纷?N|滨雇貊篬w?[u役??方挓曳4摔|嫁?\ㄕe彛黺睇{璻??猠
眕穥寕欧?嵟擎/ ?;骓
坯璟飡k,s貓?€[fi煏?煫_磺Y.6棡+NGW9槽ji髼 y鉶?y?10?昨>沲肪rXm+?= 釄h
m?溬轱/?#窊?协yG?凉兇羸縢?本k齿t蕵?煶d&刕鰘偏菫?$牚朓q咿?減辊?F俑{钪?燷寈馍?@狹龎R细k?W頄走
只示u雧昬?涌髕}O0孥萧煰Z~ ?蛜?汯?#搢O[?骪?案鶍寃瑐r圍氳p幌J羔~W艷=狲乜Os倆汾JCz耉阁G
蚤旕凈O2v5濘22x2;}缝褞顄蝤??y'竝潎?靌鈧赽孵u牎熾搽$垘?Z?mz?(??S粛莘鎰??津芣彩'(wv槩LAy衲%?蒿?OH懾?9踅儇齠?o祕_c檽契镏1E嚢Wg?湸w?諫冪寰簶 灗逆働_?sg靽?A贆鄘%鶣∣J菑S豆?氥?嶽|糥鍡謲?茘莗L8l羉魍t>瓣WVnQB?趑柂骴糯[琧dv?錘uJ奋鈤鍀帼T鰒?j'?倉 塢'?汪&邝衻谝*S?'快$
伛-]??钘?NJ禤<
M[[
鰔犀G啥??汋?蹙?铹躏F鍝洁汞w嬜棉D1畑l?h楿?谶3d画?;茱圴j€曼Es鬻阕MZ7n戒詉€? 8咥e椪瓁螺鷠虷患?~?O`箛?n锃R鱥:官.銭賣辢鶭?┹槎抩/:掩%C灟嵈u歵?-駒{磉?砭?sE?橤a焜?嗧蜇粙?邽?邗產峞未?k)^軉柅Jh_摴顧葚\t?U瑶瀸1鬸?3?#w艴鉝硕璇=??柎醍y炋[橚竩_磿蔺Mo??雌綧藃anwwBS暰1紫磉,pR*&??铒?珥cm}堔^tS&叿澎x猑Nm?~l歟Z怦
? 壉?p
+s5}??麚魳?妻鳧滕U] P痺+,筚]橰芻?圌Kr^q獥d頡嵧E鐘S?屣9灻{腺鶯?嗩?禀鉿l?昡淧筼慚践t渃,夨嫨鍵o?io)3x17锵_诪iaUC 牑?箧u輾靓Q丶;? €?產IB?潤凤l<|? €\/?耦馽B淌z1洼髉? €/骁髅o?覘釔b^_:?j?捱4] @巼?r^喢Ke? 骊蛧&?Y 圜魀跗季GfG???b瘂N舰 @襼嫉笴 曗! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ? ! T妱 *EB ?! €J? @ 燫$? P)B ⊕1?霌?氝 IEND瓸`?

这时我们可以使用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

题目图片:

misc5.png

这肯定不是真正的flag,我们需要寻找隐藏在图片里的flag,拉进winhex:

我们在ASCII区的最后发现了隐藏的flag。

misc6

题目图片:

misc6.jpg

继续winhex:

我们借助搜索工具,搜索ctf得到了flag的位置。

misc7

题目:

misc7.jpg

依旧在winhex里直接搜索flag就能找到。

misc8

题目:

misc8.png

这次,我们直接用winhex搜索并没有找到,然而,当我们搜索png文件头89504E47时,惊人的发现居然存在两个文件头:

这么看是在这个图片里面还隐藏着一个图片,我们可以进行手动分离,下面是两种不同的操作:

一种是把第二个的文件头以后全部复制,新建一格空白的文件,全部复制进去,保存可以得到图片。

另一种是直接去掉第二个文件头之前的所有信息,保留后面的信息。

最终,我们得到了隐藏的图片,获得flag。

misc9

题目:

misc9.png

在winhex里搜索flag就直接搜索到,非常简单。

misc10

题目:

misc10.png

这题在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
2
3
4
5
6
7
8
t='ct¹f…s†hªoKw°{!aeS6¥eT446xc%4Ý8ïf«73•9b‚7ºeEb|2Td~1:däeñ6úeõ412fT8ñ329éal}'
i=0
while 1:
print(t[i],end='')
i+=2
if i>len(t)-1:
break
#ctfshow{ae6e46c48f739b7eb2d1de6e412f839a}

提交了几次都没过……

网上都直接用的十六进制源码转化的:

1
2
3
4
5
6
7
8
t='631A74B96685738668AA6F4B77B07B216114655336A5655434343678632534DD38EF66AB37103395391F628237BA6545627C3254647E313A64E465F136FA65F5341E3107321D665438F1333239E9616C7D'
i=0
while 1:
print(chr(int(t[i:i+2],16)),end='')
i+=4
if i>len(t)-1:
break
#ctfshow{ae6e46c48f739b7eb2d1de6e412f839a}

最后看了一下不知道为什么很多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
2
3
4
5
6
k=[3902939465,2371618619,1082452817,2980145261]
key=''
for i in k:
key+=hex(i)[2:]
flag='ctfshow{'+ key + '}'
print(flag)#ctfshow{e8a221498d5c073b4084eb51b1a1686d}

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。

计算什么的,交给网站就行了:

时间戳(Unix timestamp)转换工具

经过转换,我们得到了 874865822 2699237688 2156662245 460377706 四个数,接下来转16进制组合就得到flag了:

1
2
3
4
5
6
k=[874865822,2699237688,2156662245,460377706]
key=''
for i in k:
key+=hex(i)[2:]
flag='ctfshow{'+ key + '}'
print(flag)#ctfshow{3425649ea0e31938808c0de51b70ce6a}

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
2
3
4
5
6
7
8
9
10
import struct
import zlib
for i in range(4096):
for j in range(4096):#i是宽,j是高,顺序不能颠倒
c = bytes.fromhex('4948445200000384000000960806000000')
ihdr = c[:4]+struct.pack('>i',i)+struct.pack('>i',j)+c[12:]
crc = 0xEC9CCBC6
if zlib.crc32(ihdr) == crc:
print(i,j)
break

如何理解这个脚本?

在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
2
3
4
5
6
7
8
9
10
import struct
import zlib
for j in range(4096):
i=900
c = bytes.fromhex('4948445200000384000000960806000000')
ihdr = c[:4]+struct.pack('>i',i)+struct.pack('>i',j)+c[12:]
crc = 0xEC9CCBC6
if zlib.crc32(ihdr) == crc:
print(i,j)
break#900 606

得到了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部分组成:

  1. 位图文件头(bitmap-file header)

  2. 位图信息头(bitmap-informationheader)

  3. 颜色表(color table)

  4. 颜色点阵数据(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
2
3
4
5
6
7
8
9
10
import struct
import zlib
for i in range(4096):
j=150
c = bytes.fromhex('4948445200000384000000960802000000')
ihdr = c[:4]+struct.pack('>i',i)+struct.pack('>i',j)+c[12:]
crc = 0xE14A4C0B
if zlib.crc32(ihdr) == crc:
print(i,j)
break#1044 150

得到的长宽修改好之后就得到了flag。

misc33

提示:出题人丧心病狂,把高度也改了

给的是png图片,还是得用脚本,这次同时爆破高和宽:

1
2
3
4
5
6
7
8
9
10
import struct
import zlib
for i in range(4096):
for j in range(4096):
c = bytes.fromhex('4948445200000384000000960802000000')
ihdr = c[:4]+struct.pack('>i',i)+struct.pack('>i',j)+c[12:]
crc = 0x5255A798
if zlib.crc32(ihdr) == crc:
print(i,j)
break#978 142

得到正确的高和宽,修改得到flag。

misc34

提示:出题人狗急跳墙,把IHDR块的CRC也改了,但我们知道正确宽度肯定大于900

给了一个乱码图片,我们需要修复这张图片,这里需要知道一点:即使crc不对,长宽对了也能正确显示图片。

所以我们可以根据题目的提示,直接试比900大的宽,从中找到一个合适的:

1
2
3
4
5
6
7
8
9
10
import struct

with open("misc34.png", 'rb') as f:
img = f.read()
for i in range(901,1200):
title = str(i) + ".png"
f1 = open(title,"wb")
img1 = img[:16]+struct.pack('>i',i)+img[20:]
f1.write(img1)
f1.close()

这里写了个脚本,把高大于900的一部分图片每个都生成出来,我们能从一堆黑色照片里面找到一个含有flag的图片。

misc35

提示:出题人负隅顽抗,但我们知道正确宽度肯定大于900

题目给的是jpg图片,这题我先按照上次的方法爆破了一次,发现都是空白图片,并没有成功,难道是高度的问题?

我把图片的高度调到600,发现图片上出现了乱码,看来是高度上也做了手脚,现在调整完之后再爆破一遍,在宽度为993开始的几张图片上都出现了flag:

1
2
3
4
5
6
7
8
9
10
import struct

with open("misc35.jpg", 'rb') as f:
img = f.read()
for i in range(901,1200):
title = str(i) + ".jpg"
f1 = open(title,"wb")
img1 = img[:159]+struct.pack('>i',i)[2:4]+img[161:]
f1.write(img1)
f1.close()

注意jpg图片宽高的位置和长度和png的有所不同,可以使用010找好位置之后再改脚本。

misc36

提示:出题人坦白从宽,正确的宽度在920-950之间

这题给的是gif格式的图片,用010的时候注意动图的大小和帧图片的大小的位置不一样,这个图片只有一帧,所以我们先改这一帧的高,发现乱码,接着爆破:

1
2
3
4
5
6
7
8
9
10
import struct

with open("misc36.gif", 'rb') as f:
img = f.read()
for i in range(920,950):
title = str(i) + ".gif"
f1 = open(title,"wb")
img1 = img[:37]+struct.pack('>i',i)[2:4]+img[39:]
f1.write(img1)
f1.close()

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
2
3
4
5
6
7
8
9
10
11
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'

list=t.split(' ')
a=''
for i in list:
if i=='37':
a+='1'
else:
a+='0'
for i in range(0,len(a),7):
print(chr(int(a[i:i+7],2)),end='')

观察代码可以发现每个字母对应7位2进制,约去了第一位0,转化的时候需要注意。

misc40

提示:flag就像歌,有长有短仿佛岁月悠悠

题目给了一个png图片,用honeyview查看发现是个动图,但是identify无法分解png格式的图片,从网上找了一个APNG分离器用来分解。

总共68张图片,分解完后给了每一个图片的帧间隔,图片里没有flag,看来就跟这个帧间隔有关了,好多图片的帧间隔所给的第一个数值都不一样,跟ASCII码很相近,那就转化一下试试:

1
2
3
4
5
6
7
8
9
for i in range(1,69):
if i<10:
name='apngframe0'+str(i)+'.txt'
else:
name='apngframe'+str(i)+'.txt'
with open(name) as f:
s=f.read()
num=s.split('/')[0][6:]
print(chr(int(num)),end='')

得到的输出里前面有一些乱码可以忽略,flag在后面。

misc42

提示:flag有多长?2cm……不好意思打错了,41位

在010里查看图片,发现有很多的IDAT块,没啥思路的时候我又用了用tweakpng,发现这个IDAT块很像和ASCII码对应:

把这些length值转化成ASCII码:

1
2
3
4
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]
for i in num:
if i in range(33,127):
print(chr(i),end='')

有一些多余的数字,忽略即可。

misc43

提示:错误中隐藏着通往正确答案的道路

我们先寻找寻找有什么问题,用tweakpng打开发现好多crc码报错:

1
2
3
4
5
6
7
8
9
10
11
12
is e59387e5, should be 8385f691
is 93a62e63, should be 42434298
is 74667368, should be 4462c3a1
is 6f777b36, should be 397611e1
is 65623235, should be 4f02afa2
is 38396666, should be defed27f
is 66663565, should be 04f13ec2
is 33393066, should be 665b7bef
is 65366238, should be 66671da0
is 37353034, should be 9922f98f
is 64626330, should be 26bc187a
is 3839327d, should be ee9d6cb4

我猜测flag就藏在这些数字里,我先用我们的flag头来引一下:

1
2
3
4
5
from Crypto.Util.number import *

b=b'ctfshow{'
print(hex(bytes_to_long(b)))
#63746673686f777b

通过一些查找等方法,我们发现错误的crc码组合起来就含有flag,我们来转化一下:

1
2
3
num='e59387e593a62e63746673686f777b36656232353839666666663565333930666536623837353034646263303839327d'
print(long_to_bytes(int(num,16)))
#b'\xe5\x93\x87\xe5\x93\xa6.ctfshow{6eb2589ffff5e390fe6b87504dbc0892}'

misc44

提示:错误中还隐藏着坑

估计还是上一题的方法,尝试提取一下crc信息,结果一下子来了100多个报错,试了一下也发现找不到flag,看来不是这种方法。

看了一下大佬wp,上面使用了一个叫pngdebugger的程序来分析,源码地址:文件png-debugger · GitCode

我们在debug文件夹下使用cmd使用程序,使用指令pngdebugger img.png > 1.txt来得到文本式的crc反馈信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
......
0x00004455 chunk-length=0x00000480 (1152)
0x00004459 chunk-type='IDAT'
0x000048DD crc-code=0x238597F3
>> (CRC CHECK) crc-computed=0x238597F3 => CRC OK!


0x000048E1 chunk-length=0x00000480 (1152)
0x000048E5 chunk-type='IDAT'
0x00004D69 crc-code=0x1255BA67
>> (CRC CHECK) crc-computed=0x25BE9607 => CRC FAILED


0x00004D6D chunk-length=0x00000480 (1152)
0x00004D71 chunk-type='IDAT'
0x000051F5 crc-code=0xF8D4A203
>> (CRC CHECK) crc-computed=0xF8D4A203 => CRC OK!


0x000051F9 chunk-length=0x00000480 (1152)
0x000051FD chunk-type='IDAT'
0x00005681 crc-code=0x27598826
>> (CRC CHECK) crc-computed=0x27598826 => CRC OK!


0x00005685 chunk-length=0x00000480 (1152)
0x00005689 chunk-type='IDAT'
0x00005B0D crc-code=0x0C58EA18
>> (CRC CHECK) crc-computed=0xC5AD69A8 => CRC FAILED


0x00005B11 chunk-length=0x00000480 (1152)
0x00005B15 chunk-type='IDAT'
0x00005F99 crc-code=0xEEA59158
>> (CRC CHECK) crc-computed=0x0B8AC976 => CRC FAILED
.......

总共有两千多行,其中我们能发现这里面有一些crc是ok的,有一些crc是failed的,可以联想到二进制,对其进行转换(去掉我们不需要的除了IDAT的其他模块):

1
2
3
4
5
6
7
8
9
10
11
12
with open("1.txt","r") as f:
s=f.read()
list=s.split()
flag=""
for i in list:
if i=='OK!':
flag+='1'
elif i=='FAILED':
flag+='0'
for i in range(0,len(flag),8):
print(chr(int(flag[i:i+8],2)),end='')
#ÿÿctfshow{cc1af32bf96308fc1263231be783f69e}

misc45

提示:有时候也需要换一换思维格式

给了一个png图片,题目提到了转换一种格式,BMP格式的图片的数值存储方式和排序和其他的都不太一样,需要将其转化为BMP图片,有一个及其简单的方法是利用Windows自带的画图工具,另存为BMP文件,就会自动改为BMP格式下的图片。

这个BMP图片在binwalk下能分解出flag图片。

misc46

提示:你见过扶乩吗

给了一个gif图片,发现图片内容在不断移动,这题是要用gif每帧的偏移量进行画图,偏移量可以使用identify直接获取:identify misc46.gif > 1.txt

1
2
3
4
misc46.gif[0] GIF 900x150 900x150+0+0 8-bit sRGB 2c 0.000u 0:00.005
misc46.gif[1] GIF 450x50 900x150+174+49 8-bit sRGB 16c 0.010u 0:00.008
misc46.gif[2] GIF 450x50 900x150+196+47 8-bit sRGB 16c 0.010u 0:00.008
……

得到上面的这些帧信息。写个脚本提取一下偏移量画个图即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import matplotlib.pyplot as plt

with open("1.txt", "r") as f:
frames = f.readlines()

L1, L2 = [], []
for i in frames:
i = i.strip().split(" ")
l1, l2 = i[3].split("+")[1], i[3].split("+")[2]
L1.append(int(l1))
L2.append(60 - int(l2))
print(L1, L2)
plt.scatter(L1, L2)
plt.show()

这里如果不对坐标进行调整的话出来的字符是反向的,我这里进行了60 - int(l2)操作,可以得到一个合适的图像:

misc47

提示:没见过扶乩,那你知道笔仙吗

给了一个png图片,打开看是空白,放在honeyview里看发现是个动图,APNG。

颜色通道

misc50

提示:有时候视线也要放低一点

图片上全是各种颜色的色块。

既然是颜色通道有关,先打开stegsolve:

大致用法是:先切换不同的颜色通道,查看图片,可能会直接显示在颜色通道的图片上,或者暴露出隐写痕迹。

打开后下面的两个键可以切换色彩通道,随便点点发现在Blue plane 2发现了一个图像:

但是flag并不全,这像是最后一节,继续又在Green Plane 0和Red Plane 1发现了flag: