L3HCTF 留档
比赛情况
- 比赛时间(UTC-8):2021-11-13 09:00:00 ~ 2021-11-15 09:00:00,共计 48 h
- 比赛模式:解题模式(动态分值,无一血奖励)
- 队伍总分:6016
- 队伍排名:7
- 贡献分数:0
前言与吐槽
第一次打正儿八经的 CTF,因为 Misc 方向没人做所以想去试试。
其实就是我啥都不会还想凑热闹而已
不过很遗憾,从各个队伍的解题情况来看,这次 Misc 除了签到题就没有什么能写的题目。
我只看了一道题目 BootFlag,从 13 号上午 10 点一直看到 14 号晚上睡觉。中途善良的 cwz 大爷前来支援,给了我巨大的精神激励。结果还是没写出来。长达 3 页半的 Google 文档生动形象地展示了我当时有多么发狂。
不过这道题难度确实不低,貌似到比赛结束为止,这道题也就只有 5 个队伍解出来。
(然而其他 Misc 更是重量级……)
当然,如果是那种一点希望都没有的 “做不出来”,那我就不会在这里写留档了对吧?实际上我们离完全解出题目已经不远了,思路基本上是对的,但是细节上出了一些问题。正因如此,我才想写下这篇留档,总结经验,吸取教训,争取下次还寄能写出一题。
未解出的题目
BootFlag
附件给了一个压缩包,拉下来解压缩之后发现里面装了一个视频和一个 bin 文件。bin 文件是 AMI Aptio UEFI 固件,视频是密码设置的全过程录屏。
题目要求是,提取 BIOS 中的 Administration Password 和 User Password。
从视频中可以看出,两个密码都只有四位,而且题目也给了密码的取值范围,很明显是想让我们爆破。
一开始我想的是,直接通过虚拟机一类的东西加载 BIOS 固件,然后想办法自动化爆破,然而缺乏经验的我连用虚拟机加载 BIOS 这一步都无法完成,只好作罢。
而且后来才想起来,密码还是有 1M+ 种情况的,这么爆破还是不现实。
那就只能求助谷歌娘了,Google 搜索 AMI BIOS Password Recovery,可以找到如下链接:https://gist.github.com/en4rab/550880c099b5194fbbf3039e3c8ab6fd
文章的作者使用了 UEFITool 这一工具,提取了固件中存储于 AMITSESetup 模块的密文,并使用异或解密成功恢复了明文。
然而,当我们满心欢喜地敲开 BIOS 的脑壳(在 follow 上述文章的步骤前,请注意你的 UEFITool 的版本,我在这里吃了亏),提取密文,试图用同样的方法获取明文时,却明显地发现了不对劲。
首先,我们提取出的密文长度与文章中的密文长度不一致。具体来说,在忽略掉末尾的 0 之后,我们提取出的密文长度为 256 bits,而文章中的密文长度却是 512 bits。
其次,对我们获取的密文尝试进行异或解密遭到了失败。这就说明,我们手中的密文使用了另外的加密方式。
在没有提示的情况下,我们也可以猜测其加密方式。256 bits 的密文长度很有代表性。更重要的是,题目的意思很明显是让我们爆破密码。综合上述两点,最有可能符合要求的加密方式就是 SHA-256 了。
然而,现在的问题在于,经过 cwz 大爷和我的尝试,直接对明文字符串用 Python 进行 SHA-256 的爆破是没有结果的。
我想到,会不会是对面的 SHA-256 加密方式有一些奇奇怪怪的变动,从而能够适应固件的需求呢?可如果真是这样,我们又如何知道他们到底是如何进行 SHA-256 的加密呢?
两个办法,一个办法是,用 UEFITool 把负责密码的模块 AMITSE 提取出来,交给 Reverse 大佬逆掉。这就是我为什么前面说后悔没去活动室找彪哥抱大腿的原因(虽然其实我当时也没想到把固件模块直接逆掉)
当然还有一个办法,不过要结合提示来看,自己想起来还是比较困难的。在我搜索 AMI BIOS Password Recovery 的过程中,我注意到,有一个网站提到,Aptio 的源代码曾经遭到过泄露,但当时我没有在意。
然而,提示出来之后,我在 Github 上乱逛的时候,意外发现了 Aptio 泄露的源代码,正好对应了提示信息中的 Github leak。
当时好像已经是 14 号下午了,我欣喜若狂,心说我这他妈不是稳了吗?!
然后我就在这里寄了。官方 WP 里一句轻描淡写的 “仔细阅读源码” 就给我干碎了。
我的爆破代码漏了两个东西。
一个是 UTF-16 的编码。这玩意是不兼容 ASCII 编码的,我当时还在想为啥 Password 要用 UINT16,而不是 UINT8 来存储。
一个是将明文的二进制表示用 0 补全到 40 字节。
考虑到这两个因素之后,官方的 WP 的爆破代码如下:
1 | import hashlib |
运行脚本即可获得两个密码,从而解出 flag。