文章目录[隐藏]
注意:题目中出现的链接需要替换后才能访问 redpacket.kaaass.net=>redpacket.kaaass.net/archived/2020/。
没错,今年的解谜红包又lei了。由于新冠疫情,大家想必都积极响应国家号召躲在家里吧,所以我又整了这么个红包。今年的题面是:http://app.kaaass.net/Redpacket2020.zip。不过需要注意,有一个牌子写错了:’\x10/1;%=\x0f\x11W\x18b.lK’=> ‘dGhlcGlhbm8v==’。以下是题解。
Stage1 – 红石大师
题面是一个Minecraft存档,需要1.14+版本才可以打开。进入存档后,可以得到一本书:
拉开活塞后,进入到一个房间,里面放了与门、或门和非门。
之后是两个简单的红石谜题,操作就是调整拉杆。不过如果你打开存档的时候注意到了作弊没关,可以直接切换为创造模式逃课(
解开最后一个谜题之后,应该会发现地上的红石灯开始闪烁。闪烁间隔又长又短,亮灯时间也又长又短,不难猜测是摩斯电码,跟着阅读就能得到:458/26/638。没错,这就是一个坐标,而且格式正是F3调试画面中中显示的坐标格式。接下来可以通过使用tp指令/tp 458 26 638,或直接挖过去的方法达到下一关。
One more thing…
如果你感觉读电码太过困难,可以试试群里豆豆dalao的方法,用中继器引出红石信号:
另外,简单讲解下这个机器。整个机器分为两部分,即上部的摩尔斯编码部分,与下侧的活塞轮存储部分。活塞轮用来存储需要发送的数据,而摩尔斯编码则是根据活塞轮的内容进行发报。
活塞轮连接一个脉冲发生器,用来定时旋转活塞轮。活塞轮的原理是透明方块不可被充能而不透明方块可以,详细可以参考Minecraft wiki的红石部分。
之后,活塞轮的输出被引到摩尔斯编码器。摩尔斯编码器的一侧是一个上边沿检测器,用来把活塞轮的输入转为脉冲。之后把脉冲送入编码器上方由中继器组成的时轴。
时轴上可以随时引出当前的脉冲。若需要某一刻输出1,则在玻璃上放置一个中继器即可。单个单元结构如下:
阅读当前的配置就可发现,活塞轮从输入端自左向右分别编码:/987612345。当然如果只是为了解题,你不需要看懂这个机器,只需要读摩尔斯电码即可。
Stage2 – 三位一体
来到指定坐标后,看到告示牌指示向前走。在一片黑暗中,大概会掉落到一个坑里,周围奏响了“希望之花”的旋律。定睛一看可以看到三个神秘内容的告示牌,和一个提示。
非常尴尬且抱歉的是,我还写错了一个牌子,中期更正的三个牌子内容为:
‘\x17\x05\x0f<%=%\x13TG\x0ch\x1d\x1b’
‘dGhlcGlhbm8v==’
‘\x07*>\x07\x00\x00*\x02\x03_nFqP’
最靠谱的,显然是’dGhlcGlhbm8v==’。看起来就很像base64,但是丢进解码器会发现解码失败?其实如果你了解base64,“==”实际上是用来补3的占位符,而这段内容并不需要补占位,去掉后解码可以得到“thepiano/”,果然这就是base64。现在问题就是另外两个了。其实占位符已经暗示了,这一段base64其实只是一大段base64的一部分,另外两段应该也是base64。而恢复它们的方法需要参考提示——“三位一体”。有什么东西可以合并呢?没错,就是异或,按照顺时针顺序,从’dGhlcGlhbm8v==’开始异或可以得到:
‘dGhlcGlhbm8v==’ XOR ‘\x07*>\x07\x00\x00*\x02\x03_nFqP’ = ‘cmVkcGFja2V0Lm’
‘cmVkcGFja2V0Lm’ XOR ‘\x17\x05\x0f<%=%\x13TG\x0ch\x1d\x1b’ = thYWFzcy5uZXQv
然后再按照顺时针拼接,就可以得到:’cmVkcGFja2V0LmthYWFzcy5uZXQvdGhlcGlhbm8v==’,解码得到:redpacket.kaaass.net/thepiano/。
Stage3 – 希望之花
打开网页之后,可以看到一个钢琴。
点击图片发现,这个钢琴事实上是可以演奏的。查看网页逻辑,其实相当的简单,就是点击按键之后播放“play.php?key=按键音名”。
随便请求一个(比如:http://redpacket.kaaass.net/thepiano/play.php?key=G4)会发现并不会发生什么,检查网页发现,需要带上cookie“session”才可以正常返回音频。而且返回音频后,session竟然发生了变化。研究session发现,这其实是一个base64,解码后内容类似:,,,,,A4,E4,E5,D4,B4,F4,D5,D4,E5,E4,C5,A4,G4,F4,F4,G4,G4。也就是你刚刚弹奏的内容,这强烈暗示了你要弹奏什么。那弹什么呢?还记得第二关掉到洞里面听到的“希望之花”(mi si la si #do #do)嘛?
弹奏的过程中,你可能会注意到一个奇怪的事情。比如弹si的时候,如果你是按照旋律弹奏的,那你会发现如果是mi si请求的是:http://redpacket.kaaass.net/thepiano/piano_voice/414fd923-c377-4766-a062-9009f12273ee.mp3。而直接弹请求的是:http://redpacket.kaaass.net/thepiano/piano_voice/6d4f974d-8c48-4264-887b-de68340e663a.mp3。不妨下载下来研究下。研究发现,第一个音频比第二个稍微大了一点点,并且前面的内容完全一样,而且文件末尾还能看到“redpacket2020/dest”的字样。
没错,文件末尾还隐藏了内容!事实上,弹奏中的每个音都隐藏了一段。不过mp3文件没有明确的文件尾标志,一般需要使用一些能解析文件结构的程序(如010editor)才能识别出哪一段是隐藏内容的开始。不过幸好不按顺序弹奏能获得原本的音频,因此可以直接进行比对。总共有八个音,也就是说有八段内容。按顺序拼接之后,我们就得到了下一关的题目。
One more thing…
这一关希望提醒大家,html还有一个map标签。19年中,我意外发现很多网页在实现区域点击的时候实现都乱七八糟,不同设备下定位还会偏移。其实使用map标签就能解决这个问题。
另外,因为Stage2的失误,因此在这里放了个抱歉的红包,这个红包的红包码在cookie内。
Stage4 – AWSL
如果你懒得拼接,我帮你拼了一份:http://app.kaaass.net/attachment/dest.bin。
不难发现,这是一个pyc文件,因此随便找一个在线反编译器丢进去……如果你不幸运的话,会发现报错了。这其实是因为,代码包含了一个“花命令”:新版本的类型注解。所以你需要一个船新版本的反编译器:https://python-decompiler.com/。反编译得到结果:
import requests def xor(a, b): return ''.join((lambda cur_char: [chr(ord(x[0]) ^ x[1]) for x in cur_char])(zip(a, b))) def load_asset(): url = 'http://redpacket.kaaass.net/kksk.bmp' return requests.get(url).content def check(data : bytes, key1, key2): key2 = int(key2) cipher = data[key2: key2 + 8] return xor(key1, cipher) == 'sh92a40a' if __name__ == '__main__': print('加载资源中...') data = load_asset() print('请输入密码1:') key1 = input() print('请输入密码2:') key2 = input() if check(data, key1, key2): print('密码正确!') else: print('密码错误!')
代码下载了一个资源文件,并要求输入key1和key2,key2需要是一个整数。检查时,取资源的key2处8个字节,与key1异或,若结果是’sh92a40a’则正确。
由于异或的性质,我们可以得到:xor(‘sh92a40a’, cipher) == key1。因此简单异或应该就能得到答案了。那么先把资源文件下过来康康(wp不接受bmp图片,因此博客内图片并非源文件,请自行下载)。
是熊猫人,awsl。等等,先别死,这文件1.5mb,能异或出150多万行,怎么找结果啊???
这一关解法有很多,我能想到的就有两个。如果dalao们有新的想法,欢迎评论告诉我。
方法1 – 暴力
根据代码,key1拢共8位,不难猜到这就是红包码。而红包码是8位数字,不如直接找出所有xor(‘sh92a40a’, cipher)是数字的结果。编码寻找发现,符合8位都是数字的只有一个。
方法2 – 以图搜图
所以为什么不直接找原图呢?作为bmp文件(而且是BMP_RGB),一大段文件内容都是像素点,不如直接找出原图比较一下。使用某度以图搜图找到一张尺寸一样的原图,然后转成bmp格式,发现只有几处不同(我测试的时候是2处)。用不同处偏移尝试就能获得结果。
隐藏Stage
秉持优良传统,今年也藏了一个隐藏红包,同样欢迎大家来玩,同样也回复可见2333333
刚一丢出存档,就有dalao说是不是有nbt。当时我说不是,但是其实隐藏关卡还是和nbt有些关系的。
这一次的提示是第三关的熊猫人。还有就是明明Minecraft版本要求1.14,但是关卡内容完全和1.14更新没关系——其实1.14更新了熊猫233333
使用支持nbt的工具,直接搜索panda即可。对应的数据应该存放在Anvil文件之中。如果你对文件格式感兴趣,可以查看Minecraft wiki的相关页面:区块格式。
然后,你就会发现那只熊猫其实就在出生点正下方的基岩中。它的名字是网址:redpacket.kaaass.net/sakuyayooo/。
打开网址后,得到字符串’06e7fc74‘。返回头中提示X-Hash-Type: crc32b。8位数字,当然可以直接暴力跑出来(也就1s不到的事,注意可能有前导零),不过我们也可以智取。
参考博客:http://moepus.oicp.net/2016/11/27/crccrack/。当然实现代码的时候同样需要注意前导零,没错,我特意挑了一个前面有0的红包码。
最后
算上今年,解谜红包已经整了3年了。而今年无疑是最失败的一年。没错,红包无人解出,log里Stage3只有一个请求。仔细想想,每一年我都想把红包设计的更加复杂,并且绞尽脑汁想加入更多编程中的实用内容,比如今年有base64结构、mp3结构和python花命令。但是仔细想想,红包的意义在于被收,乐趣其实体现在收的过程。像Stage2那样的关卡实在是太不和蔼了。如果明年还发红包,那一定不会再设置这种很难想的题目了(也不会搞要下载mc那么复杂的操作了)。
最后祝大家新年快乐,身体健康!也希望武汉疫情早日结束~
妙啊
不要停下来啊
宁也是加把劲骑士
太顶了