TL;DR
The checker validates the format SECCON{??????????????????} (exactly 26 bytes)
And the encrypts the 18 bytes inside the braces with a simple XOR stream derived from the 16 byte constant expand 32 byte k.
Analysis
Main logic
cmp [rbp-0x140], 0x1a ; length == 26call strncmp ; "SECCON{" prefix check, n=7...sub edx, eax ; last_char - '}' == 0call sigma_encrypt ; encrypt 0x12 bytes at buf+7call memcmp ; compare with flag_enc, len=0x12```c
Print Enter flag:1. fgets() a line into a stack buffer2. Strip the newline using strcspn(buf, "\n") and null-terminate3. Compute len = strlen(buf)4. Reject unless len == 0x1a (26)5. Reject unless strncmp(buf, "SECCON{", 7) == 06. Reject unless buf[len-1] == '}'7. Encrypt the 18-byte substring buf+7 (the bytes inside braces) into a temporary buffer using sigma_encrypt(buf+7, out, 0x12)8. Compare out against a global byte array flag_enc with memcmp(out, flag_enc, 0x12)
In C-like pseudocode```cint main(void) { char buf[0x100];
printf("Enter flag: "); if (!fgets(buf, sizeof(buf), stdin)) return 1; buf[strcspn(buf, "\n")] = 0; size_t len = strlen(buf);
if (len != 0x1a) { puts("wrong :("); return 1; }
if (strncmp(buf, "SECCON{", 7) != 0) { puts("wrong :("); return 1; }
if (buf[len - 1] != '}') { puts("wrong :("); return 1; } uint8_t out[0x12]; sigma_encrypt((uint8_t*)buf + 7, out, 0x12);
if (memcmp(out, flag_enc, 0x12) == 0) { puts("correct flag!");
return 0; } puts("wrong :("); return 1;}sigma_encrypt
Phase A: Build a 16-byte key array
The function loads 4 DWORDs from a global sigma_words and writes them byte-by-byte into a local 16-byte array (little-endian).
Looking at .data (e.g., readelf -x .data chall) shows sigma_words is literally the ASCII string: expand 32-byte k
So the 16 key bytes are -> key = b”expand 32-byte k”
Phase B: XOR each input byte with a position dependent mask
for (size_t i = 0; i < len; i++) { uint8_t k = key[i & 0xF]; // key repeats every 16 bytes uint8_t m = (uint8_t)(k + i); // add the index out[i] = in[i] ^ m; // XOR}Also see these exact operations in the assemble
That means the entire challenge reduces to Extract flag_enc(18 bytes) from .rodata Use key expand 32 byte k Decrypt with formula above
flag_enc in .rodata is the
03 15 13 03 11 5b 1f 43 63 61 59 ef bc 10 1f 43 54 a8Exploit
