Hackergame 2022 WriteUp
参加 Hackergame 喵,参加 Hackergame 谢谢喵。
前言
Hackergame 2022 是一场由中国科学技术大学主办的比赛。我在 2020 年的时候参加过一次。正好最近课不多,就花了一星期时间参加。
签到
题目要求在所给时间内在四个方格中画出“2022”并提交识别结果。打开浏览器 DevTools 并尝试提交一次结果,可以看出:
- 识别数字的功能是通过一个前端加载的 TensorFlow 模型实现的。
- 限制时间的变量在
const TIME_LIMITS = [2, 1, 0.1, 0];。(可以通过截断代理重写覆盖) - 提交结果是通过一个
GET请求实现的,参数result的值为识别结果。
所以可以直接通过修改GET请求的参数提交正确结果,修改浏览器地址栏、通过控制台、通过截断代理重写、使用curl等都可以完成签到。
猫咪问答喵
-
中国科学技术大学 NEBULA 战队(USTC NEBULA)是于何时成立的喵?
通过搜索,找到了这个结果喵。
成立于 2017 年 3 月
在赛前动员会和招新活动中好像也说过喵。
-
USTCLUG 于 2022 年 9 月承办的 SFD 活动中,第一个闪电演讲主题里,主讲人于 slides 中展示了一张在 GNOME Wayland 下使用 Wayland 后端会出现显示问题的 KDE 程序截图,请问这个 KDE 程序的名字是什么?
通过搜索,可以找到当时的 slides喵。
![Kdenlive 喵]()
答案是
Kdenlive喵。 -
Firefox 浏览器能在 Windows 2000 下运行的最后一个大版本号是多少?
不知道喵。既然是自然数,那就可以使用苏卡卡的 CC 攻击大法喵。
答案是
12喵。 -
在 Linux 内核 master 分支(torvalds/linux.git)下,找出首个修复 PwnKit(CVE-2021-4034)的 commit 的 hash 喵!
在GitHub 上的 linux 镜像仓库中搜索
CVE-2021-4034喵。答案是
dcd46d897adb70d63e025f175a00a89797d31a43喵。 -
会在终端显示
ED25519 key fingerprint is MD5:e4:ff:65:d7:be:5d:c8:44:1d:89:6b:50:f5:50:a0:ce.的 ssh 服务器的域名(形如 example.com 的二级域名,答案中不同的字母有 6 个)?带上引号在 Google 搜索
"e4:ff:65:d7:be:5d:c8:44:1d:89:6b:50:f5:50:a0:ce."喵。找到这个结果喵。可以知道服务器的 IP 地址是205.166.94.16喵。试着查询一下
PTR记录喵。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17$ drill -x 205.166.94.16
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 114514
;; flags: qr aa rd ra ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; 16.94.166.205.in-addr.arpa. IN PTR
;; ANSWER SECTION:
16.94.166.205.in-addr.arpa. 172800 IN PTR sdf.org.
;; AUTHORITY SECTION:
;; ADDITIONAL SECTION:
;; Query time: 0 msec
;; SERVER: 127.0.0.1
;; WHEN: Wed Oct 23 11:45:14 2022
;; MSG SIZE rcvd: 65答案是
sdf.org喵。 -
中国科学技术大学可以出校访问国内国际网络的“网络通”定价为 20 元一个月是从哪一天正式实行的?
找到这个结果,但是并不正确喵。
使用苏卡卡的 CC 攻击大法,得到答案
2003-03-01喵。
1 | import requests |
家目录里的秘密
VS Code 里的 flag
使用 VS Code 打开user目录,使用搜索(Ctrl+Shift+F)搜索flag{。或者使用命令:
1 | $ grep --recursive --line-number --regexp 'flag{' user |
Rclone 里的 flag
找到 rclone 配置文件 user/.config/rclone/rclone.conf。可以看到其中有
pass = tqqTq4tmQRDZ0sT_leJr7-WtCiHVXSMrVN49dWELPH1uce-5DPiuDtjBUN3EI38zvewgN5JaZqAirNnLlsQ。
这个密码并不是明文,通过搜索可以找到:
- rclone obscure 文档
- rclone obscure 源码
其中提到:在 rclone 配置文件中,明文密码通过AES-CTR对称加密与base64编码保存。这并不是一种安全的加密方式,因为 rclone 可以解密这些密码–这是为了防止偷窥。
通过源码第 17-22, 79-80 行,及go aes 库的文档
1
2 buf := ciphertext[aes.BlockSize:]
iv := ciphertext[:aes.BlockSize]
可以知道aes.BlockSize是 16。前 16 字节是iv,后面的是buf,
cryptKey是9c935b48730a554d6bfd7c63c886a92bd390198eb8128afbf4de162b8b95f638。
使用CyberChef,Recipe 使用From_Base64('A-Za-z0-9-_',false,false)和To_Hex('None',16)。可以得到:
- iv:
b6aa93ab8b664110d9d2c4ff95e26bef - buf:
e5ad0a21d55d232b54de3d75610b3c7d6e71efb90cf8ae0ed8c150ddc4237f33bdec2037925a66a022acd9cb96c4
把 Recipe 改为 AES Decrypt,填入 Key 和 IV,Mode 为 CTR,在 Input 中填入刚才得到的buf,即可得到 flag。
速通解法:在 rclone 论坛上找到这个帖子,其中有一个解密程序,填入pass的内容运行即可。
HeiLang
根据题意:A[x | y | z] = t 等于 A[x] = t; A[y] = t; A[z] = t。
1 | def heihei(hei_key, hei_val): # 元素赋值,一次不限个,嘿嘿! |
通过批量替换,使所有 HeiLang 语句调用这个函数。
Xcaptcha
通过这个验证码需要在 1 秒内计算三个加法。通过实验确定后端存在限时验证。
既然题目的验证码用于验证客户端是不是机器人在操作,那么使用机器人就能通过验证了。
1 | import requests |
旅行照片 2.0

羡慕旅行(
照片分析
1 | $ exiftool travel-photo-2.jpg | grep -E 'Exif Version |Make |Camera Model Name |ISO |Create Date |Flash ' |
- 图片所包含的 EXIF 信息版本是多少?(如 2.1)。
2.31 - 拍照使用手机的品牌是什么?
小米 / 红米 - 该图片被拍摄时相机的感光度(ISO)是多少?(整数数字,如 3200)
84 - 照片拍摄日期是哪一天?(格式为年/月/日,如 2022/10/01。按拍摄地点当地日期计算。)
2022/05/14 - 照片拍摄时是否使用了闪光灯?
否
社工入门
将照片放大后可以看到以下字样:
1 | WELCOME TO ZOZOMARINE STADIUM 頂点を、つかむ。 CHIBA LOTTE MARINES 2022 |

找到千叶海洋球场(ZOZO Marine Stadium 千葉マリンスタジアム),邮政编码 2610021 。大城市的 Google Earth 3D 数据好棒(
通过刚才的sm6115 (juice),找到手机可能是Xiaomi POCO M3 / Redmi 9T nfc / Redmi 9 Power / Redmi note 9 4G,分辨率 2340x1080。

在地图上可以看到附近的机场有羽田空港(HND/RJTT)和成田空港(NRT/RJAA)。
由于地图信息上球场附近写着羽田,于是猜测是羽田空港起飞。接下来的航班信息找不到了。 (我又没有会员)
苏卡卡 CC 攻击大法,启动!(这是第三次了??)
简单分析请求后,写出以下代码:
1 | import requests |
还好是国内航班,且航班号数字是三位。最终得到降落机场为HIJ,航班号为NH683。
猜数字
通过查看源码,发现要让 isTalented 的值为 1,就需要控制一次猜中的误差在1e-6/2以内。
没有发现办法可以让服务器忘记上一次我猜过的状态。多次尝试后, 我不猜了, 猜测NaN,然后就拿到了 flag。
只要我猜测足够多次,就一定有一次是直接猜中的。此服务器幸免于难(x
LaTeX 机器人
纯文本
找到Hacking with LaTeX,提交\input{/flag1},得到 flag。
特殊字符混入
通过阅读 Reading files containing # characters 和 Read strings from file that contains the special character #,找到可以使用 TeX/catcode来控制 TeX 遇到特殊字符时的行为。
payload:
1 | \newread\file |
Flag 的痕迹
页面的 Revisions 被关闭了,但是查看特定 rev 还是可以使用的。
使用 苏卡卡 CC 攻击大法,通过找到特定 rev 来获取 flag。
1 | import requests |
找到 rev 有 [1665224447, 1665224461, 1665224470],其中 1665224461 有 flag。
救救服务器!另一种解法是使用比较功能(do=diff),可以直接得到 Revisions…
安全的在线测评
无法 AC 的题目
阅读判题脚本后可以发现,静态数据的输入在data/static.in中,输出在data/static.out中。写一个 C 程序,读取data/static.out并输出就可以 AC 了。
1 |
|
动态数据因为读不到(为什么会变成这样呢?有了 0700 权限的动态输入,有了 0700 权限的动态输出,两份快乐的事情重合在一起;而这两份快乐,又给我带来更多的快乐。得到的,本该是……),不知道怎么 AC。
线路板
打开 Gerber 文件,略微调节,发现 flag。(我使用的是 KiCad Gerber Viewer)

Flag 自动机
运行 exe,发现“狠心夺取”按钮会避开鼠标,不让我点击。那么我使用触摸屏是不是就可以了呢?
很快啊,一个远程桌面配置,一个手机连接,发现可以点击到了。按传统功夫的“点”到为止它已经输了,应该给我 flag。

我关远程桌面的时间不点了,它突然告诉我“您不是本机的超级管理员”(我在使用 Administrator 账户)。我大意了啊,没有逆向改它函数。这个 flag 自动机不讲武德,我劝它好自为之,好好反思,以后不要再犯这样的小聪明。
后续通过逆向并 Patch Program 得到 flag。 不会 binary 题,调了好几个小时
微积分计算小练习
打开练习网站,发现有 5 道微积分计算题。 那么就先把它们都做出来吧
代码使用 SageMath,题目要求四舍五入,保留一位小数,可以使用round函数。(不想做题可以跳过此部分)
1 | from sage.symbolic.integration.integral import definite_integral # 导入定积分函数 |
成功获得了 100 分。
从微积分的世界返回到 CTF 的世界,调试网页并阅读后端源码发现:
- 成绩页面存在 XSS 漏洞。
- 成绩页面的姓名与分数在 URL param 的 result 中通过 base64 编码。(以及 URL Encode)
- 提交练习成绩的页面会使用 selenium 控制 Chrome,打开成绩页面处理成绩后输出。
- flag 在后端 Chrome 的 cookie 中。
构造 payload 如下:
1 | <img |
通过 base64 编码,URL Encode 后,修改 URL 并在提交练习成绩的页面提交,得到 flag。
杯窗鹅影
flag1
写一个 C 程序,读取/flag1并输出。使用x86_64-w64-mingw32-gcc编译并上传。
1 |
|
原来可以读到的吗,震撼我一整年
flag2
在 GitHub 搜索 wine exploit,找到 schlafwandler/attacking_wine 仓库。
使用Part_I/exec_shellcode.c中的代码,替换 shellcode,编译并上传,得到 flag。
蒙特卡罗轮盘赌
题目需要猜测程序运行结果,五局三胜。阅读源代码,发现其使用时间作为伪随机数生成器的种子,因此可以在本地生成最近时间的随机数。
先修改原来的代码,使其在有参数时,使用 argv[1]作为种子,否则使用当前时间作为种子。
1 |
|
编译后写一个 python 程序调用它生成最近时间作为种子的随机数,并输出到文件中。
1 | import os |
基于服务器给出的前两次结果,推测出后三次的结果,从而得到 flag。
惜字如金
HS384
先尝试补全被惜字如金化的代码,如果使用具有代码补全和错误检查功能的 IDE 会更方便。发现secret = b'ustc.edu.cn'和它的 sha384 被惜字如金化了。已知secret长度为 39。阅读惜字如金化规则,找出所有可能的secret,并计算它们的 sha384,生成类似于彩虹表的文件。
1 | from hashlib import sha384 |
单线程 python 慢慢地跑了十几分钟,生成了 106MB 的文件。 Python 3.14 将比 C++ 还快(误) 运行结束后在表中查找与题目给出的 sha384 值相似的值,得到secret是usssttttttce.edddddu.ccccccnnnnnnnnnnnn。
把secret和secret_sha384填入HS384.py,并用它来签名所需签名的数据,提交后得到 flag。
光与影
因为我在 Linux 环境下的 Chromium 无法正常渲染,所以使用 Firefox 和 Charles 来调试。
通过不断调试fragment-shader.js,最终可以得到 flag 的重写规则为:
1 | < vec4 pTO = mk_trans(35.0, -5.0, -20.0) * mk_scale(1.5, 1.5, 1.0) * pH; |
在截图中,我还启动了以下重写规则,不影响 flag 查看。
1 | < return vec3(0.0, 0.0, 0.0); |

片上系统
引导扇区
使用 PulseView 打开 zip 文件,点击Add protocol decoder,选择SD card (SPI mode),配置解码器参数后,在Binary Decoder Output View中可以看到 flag。

量子藏宝图
呜呜,不懂量子
第一章要求使用名为 BB84 的量子密钥分发协议,协商出密钥。多次尝试后我的做法是制备基底填写 30 个x,量子态填写 30 个0。提交量子态后,根据返回的测量基底中的x的个数,填写相应个数的0。(如果制备基底填写+就填写返回的测量基底中的+的个数的0)
第二章给出了一个藏有 flag 的 Bernstein-Vazirani 算法的量子电路图。我哪里懂什么量子电路图呢,只好先把电路图按行转写成了这样的格式,总共为 128 行,图中最后一行暂时不管,节点使用+表示。以下为末 8 行:
1 | 0 |
因为最后一行是左边是 x,按照电路加入到前面的规则的话,就把+替换成了 x,末 8 行如下:
1 | 0 |
已知FLAG 是 flag{...} 的形式,使用 ASCII 编码,按大端序存储。q_127 对应第一个比特,那么需要把每行二值化。又已知部分明文(flag{和}),调试后使用以下代码输出二进制:
1 | with open('q2.txt', 'r') as f: |
得到结果(为使结果美观添加了空格和换行):
1 | 01100110 01101100 01100001 01100111 |
使用 ASCII 转换为字符后得到 flag。
企鹅拼盘
这么简单我闭眼都可以
需要输入四位二进制数,总共也就 16 种可能,直接手动枚举即可。
大力当然出奇迹
通过修改 Python 源代码,使chal函数增加一个参数,输入 16 位二进制元组,并修改使它直接输出info字典,通过字典中的scrambled判断是否成功。
1 | for input_tuple in itertools.product([0, 1], repeat=16): |
火眼金睛的小 E
有手就行
手动使用 BinDiff 完成。
后续题目试了好几天,可惜没能解出来,只差 bindiff 的命令行输入和输出了。找到了 ida_haru 但是没成功跑起来。
以下是不完整的解题代码:
1 | import os |
总结
比赛好卷,不懂 math 不懂 binary 卷不过但是上榜了()

在做“蒙特卡罗轮盘赌”题目的时候,发现正好度过了时间Tue 25 October 2022 02:57:46 UTC,其时间戳为1666666666!
明年可能会再来参加,希望到时候也能够顺利上榜。
参加 Hackergame 喵,参加 Hackergame 谢谢喵。
See also
- 参加 Hackergame 2022 的一些感想和部分题解 by 柏园猫
