Skip to content

【2022篇+WriteUp】如何再收一个新年红包?

Published: at 17:27

ToC

题面

这么多年,总算是把新年红包的题弄出来了。值此除旧迎新之际,希望大家新年快乐,玩得开心(x

地址:https://triangle-2022.mmf.moe/

解密平台基于 Triangle 创建,不过估计明年还得重构如果明年还有

如果提示红包码不存在,请在本文下留言,并附上题目的编号(如 #3)。为了延长红包的存活时间(24小时),后面题的红包我会在前面题有人做出来之后再发(

如果网址打不开,请检查自身与 Cloudflare IP 的连通性情况,可以更换网络条件重试(如流量);也可以 尝试等待一段时间(可能是 DNS 没有生效)。

赛后题面将会公布于 https://github.com/Yesterday17/triangle-2022,WriteUp 则会在本文更新。

Hints

  1. #2 中1指的是0x1,表示的是加密时的顺序。工具建议使用 010Editor 和 CyberChef
  2. #4 中 UUID(不含前后缀)的 3、4和5、6位,19和20位、29和30位的位置需要交换(不含横杠,从1开始),希望 jxw 赶快重构
  3. 追记:19:50 群友已经 AK 了(
  4. #3 不涉及条件竞争

Writeup

红包生效时间过了,也该发 WriteUp 了(笑)

#1 サヨナラから始まる物語

作为签到题,flag 是通过藏头的方式隐藏起来的。简单拼接一下,顺利拿到 32 位的 hex。提示里说到 UUID 可能是 32 位无横线的形式,其实就是这题用到了。

得到的结果是 2fb4552d826a4e288ef4-911a719b271a,可以直接作为地址使用,也可以自行补上横线。

「サヨナラから始まる物語」是 「IDOLY PRIDE Collection Album [約束]」 的第一首,怀揣着种种思绪告别旧的一年,希望新的一年大家能够好好活着。

#2 MOLE

这题的起源是 MORA 上下载的音频里总是有一些意味不明的 UUID,再加上 Project Anni 对 FLAC 的研究,于是就出现了这一题。

Hint 里提示了可以使用 010Editor,但实际上我推荐的是 anni。输入:

Terminal window
anni flac export -t=all mole.flac

结果如下:

METADATA block #0
type: 0 (STREAMINFO)
is last: false
length: 34
minimum blocksize: 4608 samples
maximum blocksize: 4608 samples
minimum framesize: 3392 bytes
maximum framesize: 23824 bytes
sample_rate: 48000 Hz
channels: 2
bits-per-sample: 24
total samples: 5916672
MD5 signature: c420c52e09e69781bd746c70177bb07d
METADATA block #1
type: 4 (VORBIS_COMMENT)
is last: false
length: 139
vendor string: rot13(xor(1))
comments: 3
comment[0]: title=Rick Astley - Never Gonna Give You Up [HQ]
comment[1]: encoder=Lavf58.76.100
comment[2]: q5415ps8,853q,5703,n453,q84227or26n8=
METADATA block #2
type: 1 (PADDING)
is last: true
length: 8151

可以看到,METADATA block 中的 vendor stringrot13(xor(1)),而 comment[2] 是一个奇怪的字符串。于是按照 vendor string 中的编码方式反推回去:

得到下一题的 UUIDc4504de9-942c-4612-b542-c95336af37b9

#3 Touch The Flag

本题的源码在:https://github.com/Yesterday17/triangle-2022/tree/master/layered-flag-toucher

之前在公司有听到 OverlayFS 相关的内容,印象中 Rust 的 VFS 好像也有相关的内容,于是就去具体了解了一下。结果不看不知道,一看发现这实现还是有不少问题的。

OverlayFS 简单来说就是一个分层的文件系统。在这个文件系统中,只有最顶层是可读可写的,除此之外的各层均为只读。在读取时,指定的文件名如果在上层存在,就返回上层的文件内容,否则就依次在下层寻找,直到最底层也不存在对应文件时表示文件不存在。

概念很明确,但 Rust VFS 中的实现却非常 buggy,如:

https://github.com/manuel-woelker/rust-vfs/blob/88adee16135466fefcaa8de9a4f5403cb9d6670d/src/impls/overlay.rs#L43
https://github.com/manuel-woelker/rust-vfs/blob/88adee16135466fefcaa8de9a4f5403cb9d6670d/src/impls/overlay.rs#L43

所有和路径相关的操作都会用到 read_path,但却通过 [1..] 截掉了第一个字符,表示限定了只能使用绝对路径。

另一个就是本题利用的核心:

https://github.com/manuel-woelker/rust-vfs/blob/v0.5.1/src/impls/overlay.rs#L66
https://github.com/manuel-woelker/rust-vfs/blob/v0.5.1/src/impls/overlay.rs#L66

为了表示文件的删除,VFS 的实现使用了 whiteout 的概念。在 .whiteout 目录下如果存在对应的文件,则表示该文件实际已被删除。通过这种方式,实现了文件的“隐藏”。

这种实现出现是因为 Overlay 的下层是只读的,只有顶层可写。于是 Rust VFS 就选择在可写的 write_layer 上通过 .whiteout 目录的方式写入一个用于隐藏文件的目录。但!是!这个 .whiteout 目录也是可以正常写入的。于是就造成一个问题,在特定条件下,用户可以通过在 .whiteout 目录中「创建」文件,达到形式上「删除」文件的效果。

分析

题目给出了两个接口,一个是读取 flag/flag,一个是创建文件的 /touch。于是根据上图中的命名规则,我们只需要创建 flag.lock 对应的 flag.lock_wo 就可以了:

然后就可以读到 flag 了:

#4 Minyami

艺术来源于生活

Minyami 的介绍可以去看网商的这篇博客网商到底有哪些人.jpg

简而言之,Minyami 就是一个多线程下载 m3u8 的工具。m3u8 是播放列表,指向实际的播放视频分块(ts)。在直播情况下,通过对 m3u8 的不断请求就可以得到一份持续更新的播放列表,其中的 ts 就对应 了直播流。m3u8ts 的顺序就代表了实际拼接时的块顺序

如果下载的过程没有任何问题倒还好,但如果遇到了错误,该怎么办呢?Minyami 有错误重试的功能,在错误情况下可以通过重试。但如果一直失败呢?在我当时使用的版本,某一个块的错误就会导致不断的重试,进而使得 Minyami 无法进入下一步的合并阶段,而合并所需要的块顺序又只在内存中存在。如果你下的源对应的 ts 又正好不是顺序数字命名,那么恭喜——你这个源就下废了(

当时我也试图通过日志分析的形式对视频进行复原,但最终还是失败了,于是就有了这次的这道题。题目对应的源码在 https://github.com/Yesterday17/triangle-2022/tree/master/minyami,是一个简单的 http 服务器,接口有返回 m3u8/ 和返回 ts/flag_{id}.tsflag 的每一位对应一个块文件。对块文件的请求有 2/3 的概率会返回 403 Forbidden,只有 1/3 的概率会正常返回文件。

我们知道,Minyami 是顺序尝试下载块的,因此下载和失败的顺序一定程度上可以反映实际的块顺序。因此我们将日志文件中所有出现的块文件名称题取出来,并进行 unique 操作,只保留第一次出现。

将得到的块顺序保存在一个文件中(如 r.txt),并使用命令输出:

Terminal window
cat r.txt | xargs cat

得到一个看上去非常像是正确答案的东西:mmf{bd77014d-f4a1-475f-ae3c-8f5019c498ee}但它不对(逃

查看 Hint,我们把 flag 中的某些位调换一下位置,就可以拿到真正的 UUID 了。

结语

现在看到红包码也没用了,都过期了(
现在看到红包码也没用了,都过期了(

整场的领取情况是:14/30,11/15,3/8,2/5;四个红包的面额分别是 1.14,5.14,8.10,19.19(哼,哼,啊啊啊啊啊啊啊啊啊

红包的题面有一些陈述不清的地方,不过在群友们的帮助下在 Hint 里补了不少澄清和提示。毕竟是图一乐的玩耍场,#1 和 #2 本来是想着大家开心一下的,没想到没领完,明年还要弄简单点

我的本意是把红包码放在 HTML 的注释里的,这样既不影响截图也不影响领取。结果吃完年夜饭一看没人领,后来才发现是 Cloudflare 的压缩把注释都干掉了,于是又加急放回了题面里,麻了。

第三题的环境一开始没有重置,导致在 KAAAsS AK 了之后后续的解题者就算有了正确答案也会显示 flag is stolen。后来才补上了脚本。

总而言之,这次的题面我个人还是比较满意的,想到的脑洞基本上都弄出来了#4 应该是比 #3 要简单上一些,但不知道为什么有人只做了 #3(。这次题面里没有逆向,整体也偏 MISC 一些,希望明年能百花齐放两开花或者也可以跟群友一起出?(

总之,虎年也如期而至。在这篇咕到初二才出来的 WP 里,给各位拜个晚年,新年快乐!

平台择日下线,想玩的这几天还能复现一下ww


Previous Post
如何将良心云的良心功能清理干净
Next Post
Grajapa Shueisha / BookEnd 加密方式调查