UMass CTF 2026 - Batcave Bitflips
Batman’s new state-of-the-art AI agent has deleted all of the source code to the Batcave license verification program! There’s an old debug version lying around, but that thing has been hit by more cosmic rays than Superman!
蝙蝠侠的新型先进人工智能代理删除了蝙蝠洞许可证验证程序的所有源代码!虽然还有一个旧的调试版本,但那东西被宇宙射线击中的次数比超人还多!
Hint 1 BatAI estimates there are 3 bugs (BatAI 估计有 3 个错误)
Hint 2 Rotation rotation rotation! (旋转 旋转)
Hint 3 Something about that SBOX seems off… (SBOX 似乎有些不对劲…)
Initial Analysis
The “Batcave Bitflips” challenge involves a binary that performs a custom hashing algorithm on a user-provided license key and compares the result to a hardcoded 32-byte hash. If the hashes match, the binary uses the key to “decrypt” the flag. However, as the name and hints suggest, the binary is riddled with three “bit-flip” bugs that corrupt its logic.
1. Analysis of main
The main function (0x169f) follows a standard license
check pattern: 1. Prompts for a 33-byte license key. 2. Calls
hash(input, buffer) to generate a 256-bit (32-byte) digest.
3. Calls verify(buffer), which compares the digest to a
global array named EXPECTED (at 0x4040). 4. If successful,
calls decrypt_flag(buffer) and prints the FLAG
global (at 0x4060).
2. Identifying the 3 Bugs
Bug 1: The Decryption Logic
(decrypt_flag) The decrypt_flag
function (0x12a6) is intended to decrypt the flag using the successful
hash. Standard encryption/decryption uses XOR, but the
decompiled code shows: - Code:
FLAG[i] |= *(_BYTE *)(i % 32 + a1); - Disassembly
(0x12ec): 09 c1 (OR ECX, EAX) The
bit-flip changed an XOR (31 c1) into an
OR (09 c1).
Bug 2: The Rotation Logic (rotate) In a
standard 8-bit rotation, the sum of the left and right shifts must be 8.
- Decompilation:
*result = (*result >> 6) | (8 * *result); -
Analysis: 8 * *result is equivalent to
*result << 3. A shift of 3 combined with a shift of 6
is not a valid rotation. - The Flip: The SIB byte in
the lea instruction at 0x1275 is 0xc5 (Scale
8). If the bit-flip occurred here, changing 0xc5 to
0x85 (Scale 4), the instruction becomes
x << 2. Combined with shr 6, this forms
a proper 2-bit rotation.
Bug 3: The SBOX Data (SBOX) The
substitute function uses a global SBOX table
(0x4080). Analysis reveals: - Duplicate: The value
0x43 appears at both index 24 and index 92. -
Missing: The value 0x44 is entirely
missing from the table. This single-bit difference (0x43 vs
0x44) in the data segment is the third bug.
Solution
While we could patch the binary to fix the bugs and attempt to
reverse the custom hash, there is a much faster path. The
main function logic implies that if we provide the
“correct” license key, the resulting hash will be equal to the
EXPECTED bytes. Since the decrypt_flag
function (if fixed) would simply XOR the FLAG bytes with
the successful hash, we can perform this operation manually.
Target Hash (EXPECTED @ 0x4040):
3b 54 75 1a 24 06 af 05 77 80 47 c5 e4 83 d3 48 cb 87 30 de 1a 91 45 ab 15 c7 9b 22 04 02 2b ee
Encrypted Flag (FLAG @ 0x4060):
6e 19 34 49 77 7d f0 5a 07 b4 33 a6 8c e6 e6 17 fb e9 6f ae 2e e5 26 c3 70 e3 c4 7d 27 7f 2b 00
1 | expected = [0x3b, 0x54, 0x75, 0x1a, 0x24, 0x06, 0xaf, 0x05, 0x77, 0x80, 0x47, 0xc5, 0xe4, 0x83, 0xd3, 0x48, 0xcb, 0x87, 0x30, 0xde, 0x1a, 0x91, 0x45, 0xab, 0x15, 0xc7, 0x9b, 0x22, 0x04, 0x02, 0x2b, 0xee] |