UMassCTF 2026 Writeup

UMassCTF 2026 Writeup

这篇文章整理 UMassCTF 2026 的几道题目。题目按照比赛名称集中记录,并在开头提供索引。

题目索引

BrOWSER BOSS FIGHT

题目分析

服务响应中直接提示了正确 key:

1
under_the_doormat

但是前端表单提交逻辑把 key 改成了错误值,然后再进行重定向。因此问题不在 key 本身,而在前端校验流程。

解法

打开浏览器控制台,临时覆盖表单的 onsubmit,让浏览器直接提交原始输入:

1
document.getElementById('key-form').onsubmit = () => true;

进入 Castle 页面:

1
http://browser-boss-fight.web.ctf.umasscybersec.org:48003/bowsers_castle.html

接下来需要找到一把斧子,砍断铁索桥的铁索。查看页面响应和脚本时,可以发现状态变量:

1
hasAxe = false

在控制台设置 Cookie 后刷新页面:

1
2
document.cookie = "hasAxe=true; path=/";
location.reload();

刷新后即可获得页面中的 flag。原始材料没有记录具体 flag 字符串。

The Accursed Lego Bin

RSA 种子恢复

明文 I_LOVE_RNG 只有 80 bit,而模数 n 为 4096 bit,因此:

1
2
m^7 < n
m^49 < n

题目中 RSA 加密的种子可以直接还原为:

1
2
3
plaintext = b"I_LOVE_RNG"
m = int.from_bytes(plaintext, "big")
seed = m ** 7

复现洗牌并逆向还原

程序使用 Python 的伪随机数生成器,以 seed * round 作为种子,对 flag 的二进制位连续洗牌 10 次。恢复时按相反顺序重建逆置换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import random


encrypted = bytes.fromhex(
"a9fa3c5e51d4cea498554399848ad14aa0764e15"
"a6a2110b6613f5dc87fa70f17fafbba7eb5a2a5179"
)
seed = int.from_bytes(b"I_LOVE_RNG", "big") ** 7

bits = []
for byte in encrypted:
bits.extend(f"{byte:08b}")

history = []
for round_number in range(1, 11):
indices = list(range(len(bits)))
random.seed(seed * round_number)
random.shuffle(indices)
history.append(indices)

current = bits[:]
for indices in reversed(history):
inverse = [0] * len(indices)
for old_position, new_position in enumerate(indices):
inverse[new_position] = old_position
current = [current[inverse[i]] for i in range(len(current))]

plaintext = bytes(
int("".join(current[i:i + 8]), 2)
for i in range(0, len(current), 8)
)
print(plaintext.decode())

Batcave Bitflips

题目分析

使用下面的命令查看 .data 段:

1
objdump -s -j .data ./batcave

可以找到 LICENSE_KEY、EXPECTED、FLAG 和 SBOX。其中 LICENSE_KEY 是明文存储的。

继续反汇编并还原流程,可以得到:

1
expand_state -> substitute -> mix -> rotate -> derive_final

题目提示程序中存在三个 bug,需要分别修复。

修复三个 bug

  1. rotate() 的移位量不一致

    原代码左移 3 位、右移 6 位,两者之和不是 8,不能构成正确的 8 bit 循环左移。将右移量改为 5,使其成为循环左移 3 位。

  2. SBOX 存在重复值

    SBOX[24] 和 SBOX[92] 都是 0x43,同时缺少 0x44。将 SBOX[24] 改为 0x44,恢复 S 盒的双射性。

  3. 解密使用了 OR

    decrypt_flag() 中使用 | 无法实现对称解密。将其改为 ^,使用异或完成密钥解密。

修复后输入密钥:

1
!_batman-robin-alfred_((67||67))

得到 flag:

1
UMASS{__p4tche5_0n_p4tche$__#}

Son of a Sith

线索分析

题目台词:

if there’s one thing I know, it’s that I hate sand

这句台词指向《星球大战》中的阿纳金·天行者和塔图因。题目场景中的沙漠洞穴里有一个红色的 2×2 乐高砖块,也就是游戏中的 Red Power Brick。

解法

在《乐高星球大战》系列中,Red Power Bricks 是关卡中的收集品。塔图因的关卡 Through the Jundland Wastes 中,红色砖块正好位于洞穴内,与题目场景相符。

该红色砖块解锁的能力是 Fast Force,因此 flag 为:

1
UMASS{Fast_Force}

Brick by Brick

解题思路

先访问 robots.txt,根据其中列出的路径找到第二个文件。题目的根目录存在文件读取参数:

1
/?file=

读取 config.php 后,可以发现管理员后台路径:

1
/dashboard-admin.php

直接读取该页面:

1
/?file=dashboard-admin.php

管理员页面会直接返回 flag。

这道题的关键是先从 robots.txt 获得文件名,再利用 file 参数读取后台页面,而不是继续围绕前端页面寻找复杂的认证绕过。