Flag: SCSC26{ai_g3n3r4tr3d_r3v3rsing_ch4ll_mu5tb_easy_r1ght}
Description: good luck
The file was a stripped static x86-64 ELF. checksec also showed no PIE, so addresses from disassembly could be used directly.
file '/home/LIGHT/Downloads/SCSC2026Final/challenge'/home/LIGHT/Downloads/SCSC2026Final/challenge: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=8d422e6806a5d87a895358f01f3f2d639ab73ff0, for GNU/Linux 3.2.0, strippedchecksec --file='/home/LIGHT/Downloads/SCSC2026Final/challenge'[*] '/home/LIGHT/Downloads/SCSC2026Final/challenge' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)Strings gave the program flow. It asks for a passphrase, rejects bad input, and prints Correct! Flag: %s on success.
strings '/home/LIGHT/Downloads/SCSC2026Final/challenge' | rg -i "flag|ctf|scsc|\{[^}]+\}|key|secret|password|BEGIN|correct|wrong|input|luck" --max-columns=200 || trueFind the secret passphrase and get the hidden flag.Wrong key, try again.Correct! Flag: %sA quick run with dummy input confirmed the passphrase gate.
printf 'AAAA\n' | timeout 3 '/home/LIGHT/Downloads/SCSC2026Final/challenge' || true== Intermediate Reverse Engineering Challenge ==Find the secret passphrase and get the hidden flag.Enter passphrase: Wrong key, try again.The interesting validator was at 0x401970. It checks a 24-byte input, transforms each byte, updates a 32-bit state, compares the low byte of rol32(state, 5) against the table at 0x47cb40, and finally requires the state before that last rotate to equal 0x262bd9e5. The table bytes were:
f6 c5 bb 5f 24 91 31 34 9d a8 05 b0 2a 5d a7 48 04 88 07 76 f6 ce c4 a4That made the check small enough for bit-vector solving. This script models the byte operations and asks Z3 for printable input.
from pathlib import Pathfrom z3 import *
b = Path('/home/LIGHT/Downloads/SCSC2026Final/challenge').read_bytes()base = 0x400000exp = list(b[0x47cb40 - base:0x47cb40 - base + 24])cs = [BitVec(f'c{i}', 8) for i in range(24)]edi = BitVecVal(0xb16b00b5, 32)s = Solver()
for c in cs: s.add(c >= 0x20, c <= 0x7e)
for i, c in enumerate(cs): r8 = (7 + 3 * i) & 0xffffffff edx = ZeroExt(24, c ^ BitVecVal(r8 & 0xff, 8)) + BitVecVal(0x4d, 32) edx = edx & BitVecVal(0xff, 32) al = RotateLeft(c, 2) ^ BitVecVal(0xa5, 8) eax = ZeroExt(24, al) eax = (eax << (((i + 1) & 3) * 8)) | (edx << ((i & 3) * 8)) eax = eax ^ edi edi = RotateLeft(eax, 5) s.add(Extract(7, 0, edi) == exp[i])
s.add(eax == 0x262bd9e5)s.check()m = s.model()print(bytes([m[c].as_long() for c in cs]))b'BUr7z2s}tX7q/mi4ll3ng3!!'Feeding that passphrase to the binary printed the flag body. The challenge prefix wrapped it as scsc26{...}.
printf 'BUr7z2s}tX7q/mi4ll3ng3!!\n' | timeout 3 '/home/LIGHT/Downloads/SCSC2026Final/challenge'== Intermediate Reverse Engineering Challenge ==Find the secret passphrase and get the hidden flag.Enter passphrase: Correct! Flag: ai_g3n3r4tr3d_r3v3rsing_ch4ll_mu5tb_easy_r1ght