前些天参加了第一届 PKU GeekGame,拿了第 21 名。这是我第一次参加 CTF,感觉还挺有趣的,分享一下 Writeup。
签到
使用可以打开 PDF 的软件(如 Chrome 等)打开,复制最下面两行到其他文本软件中,得到 1
2fa{aeAGetTm@ekaev!
lgHv__ra_ieGeGm_1}
一开始用的是 Acrobat,谁知道只能复制
{}
内部的内容,得到的是aeAGetTm@ekaev!
lgHv__ra_ieGeGm
然后就对着这个东西搞了好几天,一度怀疑人生,最后试了一下 Chrome,直接吐血......
小北问答
- 北京大学燕园校区有理科 1 号楼到理科 X 号楼,但没有理科 (X+1) 号及之后的楼。X 是?
显然为 5。也可以查百度地图
- 上一届(第零届)比赛的总注册人数有多少?
查相关微信 推送 可知答案为 407
- geekgame.pku.edu.cn 的 HTTPS 证书曾有一次忘记续期了,发生过期的时间是?
给一个 网址
- 2020 年 DEFCON CTF 资格赛签到题的 flag 是?
再给一个 网址
- 在大小为 672328094 * 386900246 的方形棋盘上放 3 枚(相同的)皇后且它们互不攻击,有几种方法?
根据这个 网页 上面给出的 m*n
棋盘上的 3 皇后问题的公式,编程计算即可。
这个问题卡了几天,一看这两个数字分别是狗妈和嘉然的 UID,还以为和她们有什么关系……
- 上一届(第零届)比赛的 “小北问答 1202” 题目会把所有选手提交的答案存到 SQLite 数据库的一个表中,这个表名叫?
去上一届的 Github 存档 可以找到,答案为 submits
- 国际互联网由许多个自治系统(AS)组成。北京大学有一个自己的自治系统,它的编号是?
直接在 相关网站 搜索即可
- 截止到 2021 年 6 月 1 日,完全由北京大学信息科学技术学院下属的中文名称最长的实验室叫?
在相关 网页 可以查到,答案为区域光纤通信网与新型光通信系统国家重点实验室
翻车的谜语人
- 用 wireshark 打开文件,过滤 HTTP 包,可以获得几个 jupyter notebook 文件和一个 flag1.txt 和一个 flag2.7z
- 分析 jupyter notebook 文件,可以发现把
flag
与一个key
做了一下异或,注意到flag1
和flag2
使用的key
是不同的,不过都可以从文件中直接得到。 - 此时就可以求出
flag1
了。直接再异或一次就行。 - 打开
flag2.7z
,可以发现压缩包加密了,且里面是一个 wav 文件。 - 为了求
flag2
,还需要过滤 websocket 包,看到先是用stego-lsb
工具把flag2
隐写到一个 wav 文件中,然后再 7z 压缩,密码为Wakarimasu!`date``uname -nom` `nproc`
- 从 websocket 的内容可以发现这个计算机叫做
you-kali-vm
,从 7z 压缩输出可以看到 CPU 是一个 8 核的 i7-10510u,操作系统是 Linux,从包到达的时间可以知道调用命令的具体时间,于是密码为Wakarimasu! Sat 06 Nov 2021 03:44:15 PM CST you-kali-vm x86_64 GNU/Linux 8
- 解压出 wav 文件,然后再用
stego-lsb
提取出flag2
,再和对应的key
异或一次就能解密出来了。
这题栽在了
PM
上,我所有时区都试过了……
叶子的新歌
- 观察 MP3 元数据,看到一个可疑内容:
aHR0cDovL2xhYi5tYXh4c29mdC5uZXQvY3RmL2xlZ2FjeS50Ynoy
- base64 解码之,得
http://lab.maxxsoft.net/ctf/legacy.tbz2
- 下载,得到一个 img 软盘文件
- 用虚拟机挂载之,得到
flag2
和一个不知是啥的密码
- 解压缩 img,得到一个压缩包
MEMORY.zip
和一个NOTE.txt
,txt 里提到密码为宾驭令诠怀驭榕喆艺艺宾庚艺怀喆晾令喆晾怀
,搜索相关内容知道这是冠号暗语,解密后解压MEMORY.zip
,得两个 bin 文件和一个含有提示的 txt - 根据提示,要找不同。把两个 bin 不同的数据按顺序拼到一块,得到一个文件,文件头有
NES
字样,再根据之前的提示使用 NES 模拟器,发现是个魔改超级玛丽 - 游玩之(指使用金手指锁命 + 随时存档 + 跳关),通关后获得新提示
- 打开网站
http://lab.maxxsoft.net/lab/ctf/leafs/
,利用之前虚拟机里的密码打开,可获得flag3
在线解压网站
这个网站可以让我们上传一个压缩文件,网站会帮我们解压。那么可以利用软连接来获得任意文件。在本地做一个软连接文件,连接到根目录下的 flag 文件 (ln -s /flag test
),压缩并提交到网站,下载解压后的文件并打开,就可以获得 flag。(甚至没有看源码)
Flag 即服务
/api/
涉及到访问文件,可以利用。因为 demo.json
位于 /data/
文件夹,我们需要访问上一级文件夹,可以用 URI 编码 ..%2f
这个漏洞。访问 /api/..%2fpackage.json
,根据 json 里的链接下载源码,打开源码看到 flag1 为 flag {${0.1+0.2}}
,计算一下就得到 flag1
(注意 0.3 无法精确表示)
诡异的网关
- 下载程序,观察发现程序里存储了一个叫 flag 的用户及其密码。显然密码就是我们需要的
flag
- 添加一个用户,可以发现密码保存在 config 文件中。
- 对比下 config 文件和 config.xml 文件,发现 config 里的部分 ASCII 字符做了加 1 或减 1 处理。定位到 flag 用户(文件中为
gmaf
),发现其密码为gmafzh1w^did_xNt^f2t_ti3^parrv0Se?|
,猜测密码为英文有意义内容,又因为加密后的 ASCII 码与加密前的 ASCII 码最多相差 1,推测 flag 为flag {h0w_did_yOu_g3t_ti3_passw0Rd?}
,提交发现正确。(我估计标准答案绝对不是这么做的)
最强大脑
根据源码发现 flag1
保存在 bf 开的数组的最后位置,使用代码 +[>.+]
(无限循环打印当前指针指向的内容)就可打印出 flag
。
密码学实践
观察源码,Richard 首先发了两条消息,使用 MESenc
函数加密。观察该函数,发现其是个分块加密,将 key 分为 32 份,循环对一块进行加密,关键代码为
1 | for key in keys: |
显然解密时只要将代码改为
1 | for key in reversed(keys): |
即可。但问题是我们并不知道 key 具体是啥。使用如下代码:
1 | keys = [1<<i for i in range(32)] |
可以分析出加解密时每个小块的 pattern。可以得到明文和密文的关系 a,b,c,d = a_cip^c_cip^k1^k3, b_cip^d_cip^k2^k4, a_cip^k1, b_cip^k2
其中
1 | k1 = a_cip^c |
这样如果我们获得了一个消息的明文和密文,我们就可以对任意密文进行解密了。而 Richard 发来的第二条消息是已知的,那么就可以推出第一条消息的内容,进而获得 flag1
对于 flag2
,因为 God 不会给我们名字是 Alice 的人的 cert
,可以进行 选择密文攻击。构造一个名字叫做 Alice,密钥是 0 的用户,分别 packmess
后连起来获得 cert
(未加密)。然后选择一个整数 \(X\),其与 \(N\) 互质,计算 cert * pow (X,e,N)
,解压出其 name
和 key
,将 name
和 key
传给 God,让他帮我们加密,获得加密后的 new_cert
。找到 \(X\) 在模 \(N\) 下的逆元,乘以 new_cert
,就获得了加密后的 cert
。将其传给 Richard,获得了新的消息。由于密钥为 0,所以 MESenc
函数使用的 key 不变,那么利用同样的方法就可以获得 flag2
了。
扫雷
困难难度实际更简单。因为困难模式不会重新生成 board
,而 board
是用密码学不安全的 getrandbits
函数生成的。参考 这个链接,我们记录下前 78 局生成的随机数(一局 16*16=256bit,78 局就能获得 624 块的数据了),然后使用 MT19937 随机数预测器(如 这个)就可以推测出后面生成的 board
了。