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) Replacing 09 c1 with 31 c1 would change OR to XOR, but the opcode difference 0x38 contains three set bits. This is a proposed repair, not proof of a one-bit flip.

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. The difference 0x43 ^ 0x44 = 0x07 changes three bits. The duplicate/missing pair suggests an SBOX defect, but does not identify the corrupted index or establish a single-bit repair.

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
2
3
4
5
6
7
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]
flag_enc = [0x6e, 0x19, 0x34, 0x49, 0x77, 0x7d, 0xf0, 0x5a, 0x07, 0xb4, 0x33, 0xa6, 0x8c, 0xe6, 0xe6, 0x17, 0xfb, 0xe9, 0x6f, 0xae, 0x2e, 0xe5, 0x26, 0xc3, 0x70, 0xe3, 0xc4, 0x7d, 0x27, 0x7f, 0x2b, 0x00]

if len(expected) != len(flag_enc):
raise ValueError("EXPECTED and FLAG must have equal lengths")
plaintext = bytes(e ^ f for e, f in zip(expected, flag_enc))
print(plaintext.split(b"\x00", 1)[0].decode("ascii"))

The XOR script reproduces the displayed flag from the two retained 32-byte arrays; the result has a NUL terminator followed by 0xee. The original binary and complete SBOX are unavailable, so the instruction patches, table repair and license verification have not been reproduced.

Flag

UMASS{p4tche5_0n_p4tche$#}