
事情是这样的,百般无聊的我在网上闲逛,看到了一篇神秘推文,神秘推文里面有一张神秘图片,神秘图片里面包含了神秘信息(什么神秘信息,不就是信息隐写嘛)。作为一只好奇心爆棚(百无聊赖)的菜狗,当然是想要解密出这张图片里面的神秘信息。万万没想到,这一尝试竟是漫长的9轮解密。接下来就一起来看一看,黑客们是如何玩信息隐写的。
神秘海报——黑客军团(信息隐写图片)
第0x1轮解密——steghide抽取文本线索:
图片我已经右键下载下来了。盯着看了一会儿,我决定先用工具Steghide碰碰运气,我的虚拟机里面的Kali有安装steghide,打开终端,输入图中命令,提示输入密码,这个暂时不知道,这里回车使用空密码碰碰运气,正所谓不怕赌狗不争气,就怕赌狗好运气。cat 查看抽取出来的answer.dat,可以看到成功获得一条新的文本线索。
steghide extract -sf Share/mr_robot.jpg
第0x2轮解密——暗藏答案的数字:
斗胆翻译了一下,我们接着新的文本线索继续往下挖掘。“下一步在这儿”......“答案近在眼前”......"跟随这些数字"。思考了好一会儿,在想这些数字怕不是上面这段文本的字符索引。”大胆假设,小心论证“,脏活累活我不干,全部交给脚本干,实现哥哥不用动,脚本全自动,还是直接写个Python脚本验证一下。数字中间还有一个"/"暂时不知道是干嘛用的,不管了碰到这个符号就先直接原样输出。脚本写完以后,运行脚本,幸运如我,又喜提一条新的线索——一条Pastebin网站的URL。
#!/usr/bin/python3 secret_msg = "Perhaps you see this and wonder what the f4ck is going on, What is this bullshit. Well, the solution is Right in front of your eyes, you just have to look closer. Just follow the numbers and you will find the answer. Did you find it?"
letter_pos = [0,4,6,16,29,72,78,99,161,155,157,181,"/",163,144,104,217,3,227,182,104] for x in letter_pos: if x == '/': print("/",end='') else: print(secret_msg[int(x)],end='') print()
第0x3轮解密——前往链接,一探虚实:
打开解密获得的URL,可以看到这一次是一串6000多行的超长字符文本。拖到页面的最后看到了一个等号,难不成是一段Base64编码过的文本?于是直接请出网络五星大厨——CyberChef料理这段文本。看decode出来的文本开头,像是一段文件头信息,感觉像一个经Base64编码过的wav格式的音频文件。解码保存到本地为audio.wav,新线索应该就藏在这段音频中。希望不是什么不堪入耳的ASMR,别问,我也不知道什么是ASMR。
第0x4轮解密——音频竟藏二维码:
怀着激动心情,特意调低了播放器音量,手抖着点开了这个音频,本来还想给大家听一下什么是ASMR,让大家失望了,只是一段噪音而已,看来新的线索并不在音频声音里面。不在音源里面,难不成在频谱里面?于是在网上找了一个频谱分析网站,上传音频,点击播放,可喜可贺,Luck me,可以看到一个内含二维码的频谱缓缓拉开帷幕。
第0x5轮解密——回到原点,又是一张图:
怀着激动心情,打开微X的扫一扫,扫描这个二维码,查看这个二维码所指向的信息,原来是一个github链接。使用浏览器打开这个链接,这个链接指向了另外一张黑客军团(美剧)的剧照图片。图片的上级目录名为Puzzle。看来又回到了原点——又是图片信息隐写。保存图片,继续挖掘。
第0x6轮解密——分析新图,找到新的加密文本:
图片下载下来以后,本以为还是用steghide隐写了信息的JPG,于是用steghide又抽取了一遍,结果没有抽取到任何信息。经网友@Aristore提点,在JPG文件末尾找到了追加的文本信息。使用xxd命令查看图片就可以看到本应该是JPG文件末尾标识的 FF D9后面,追加了一段文本信息。这里使用strings命令可以看的更清楚。
新的加密文本:
gur nafjre yvrf va gur ahzoref. Ohg lbh unir gb phg qbja gur jbbqf gurl or reqbf.
22 71 64 48 66 70 76 48 68 70 86 32 94 87 100 92 22 79 78 70 88 86 82 36 66 56 70 75 46 64
第0x7轮解密——ROT13解密新的加密文本:
一串奇怪的英文字符和一串奇怪的数字。又是看了好大一会儿,感觉像是ROT13加密,随机抽取了两三个词组,对照ROT13表尝试还原了一下,可以还原为英文单词(例如gur->the,nafjre->answser) ,应该就是ROT13加密了。于是又请出了网络五星大厨——CyberChef来料理这段文本。经过大厨的处理,杂乱的英文字母变成了有意义的英文语句。下面的数字跟着也开始变得有意义了。看来还没完,还得继续解下去。
第0x8轮解密——Erdos-Woods数:
"the answer lies in the numbers. But you have to cut down the woods they be erdos.
22 71 64 48 66 70 76 48 68 70 86 32 94 87 100 92 22 79 78 70 88 86 82 36 66 56 70 75 46 64
又是答案藏于数字,不过有个前提条件,就是得先砍掉一些woods,它们是erdos。好在我有每天学英语的习惯,语境上下文什么的还是整的明白的,一组合发现新的关键词erdos woods,这是什么玩意,我也不知道。问过AI,AI讲的好像跟我要找的信息相去甚远,看来还得靠搜索引擎。找了半天终于在一个数学网站上找到了疑似有用的信息。做为一个数学曾经考过43分的男人,这里勉为其难的为大家讲解一下,现丑了。高手请直接看论文,当一个正整数k,被认为是Erdős–Woods数,那么正整数a在连续序列中 (a, a + 1, …, a + k) ,中间的数如果与首尾的数共享任一个质因子,那么这一段连续数的长度就是Erdős–Woods数。最小的Erdős–Woods数是16。感兴趣的朋友可以自行研究下。好在论文给出了100以内的Erdős–Woods数,刚好够用,真是幸运。快速写一个脚本,砍掉新文本线索中的数字列表里面的Erdős–Woods数,获得一个新的数字列表。
#!/usr/bin/python3 '''the answer lies in the numbers. But you have to cut down the woods they be erdos. 22 71 64 48 66 70 76 48 68 70 86 32 94 87 100 92 22 79 78 70 88 86 82 36 66 56 70 75 46 64 ''' secret_nums = [22,71,64,48,66,70,76,48,68,70,86,32,94,87,100,92,22,79,78,70,88,86,82,36,66,56,70,75,46,64] erdos_woods_nums = [16, 22, 34, 36, 46, 56, 64, 66, 70, 76, 78, 86, 88, 92, 94, 96, 100] after_cut_down = [num for num in secret_nums if num not in erdos_woods_nums] print(after_cut_down)
第0x9轮解密——砍掉杂数,解余数:
经过上一步,砍掉Erdős–Woods数后,获得一个新的数字列表。目前还不知道这些数字有什么用,一开始我以为像第一轮解密那样,数字代表字符索引,后来发现,精减过的数字列表最大数是87,而 “the answer lies in the numbers. But you have to cut down the woods they be erdos.” 这条文本却只有81个字符,明显超限了,看来不是字符的索引值。看了好一阵子,大脑突然闪过一个念头,这些数字刚好都在Ascii字符的十进制值的区间范围内。可能是Ascii字符的十进制值。说干就干,迅速修改上面的脚本验证一下。运行脚本,可以看到“G00D WORK”的正确提示。
#!/usr/bin/python3 '''the answer lies in the numbers. But you have to cut down the woods they be erdos. 22 71 64 48 66 70 76 48 68 70 86 32 94 87 100 92 22 79 78 70 88 86 82 36 66 56 70 75 46 64 ''' secret_nums = [22,71,64,48,66,70,76,48,68,70,86,32,94,87,100,92,22,79,78,70,88,86,82,36,66,56,70,75,46,64] erdos_woods_nums = [16, 22, 34, 36, 46, 56, 64, 66, 70, 76, 78, 86, 88, 92, 94, 96, 100] after_cut_down = [num for num in secret_nums if num not in erdos_woods_nums] print(''.join(chr(x) for x in after_cut_down))
为了确切的保证题目解完,事后我还专门去找发布海报的推主,去确认了一下,推主给出了Yes的回复。看来到这里,这张有隐写信息的神秘海报JPG,经过9轮信息解密,总算是告一段落。CTF比赛中偶尔也会出现信息隐写类的题目,后面如果碰到了再跟大家分享,我是虫一卜。Happy Hacking~
附录:
神秘海报下载:https://github.com/cyibu/re/blob/main/mr_robot.jpg
Erdős-Woods number:https://planetmath.org/erdhoswoodsnumber
CyberChef: https://gchq.github.io/CyberChef/