Flag Aperisal

Challenge Overview

We are given a binary that reads a flag, transforms it using sub_1199, and then compares the mutated buffer against a constant target (s2) using:

if ( !strncmp(s, &s2, 0x25uLL) )

So the goal is clear: We must reverse the transformation performed in sub_1199 and recover the original input that produces the expected transformed bytes.

The core transformation loop is:

v3 = (257 * input[i]) ^ (509 * input[i+1]) ^ (33 * v3);
*(_WORD *)(i + input) = v3;

Critical observations:

  1. v3 is __int16 → 16-bit

    • Every iteration implicitly works modulo 2^16.

    • Without applying & 0xFFFF in Python, the brute-force breaks after the first block.

    • This was the most important technical detail.

  2. Little-endian write

    *(_WORD *)(i + input) = v3; //WORD = 2 BYTES

    means:

    input[i]     = low byte
    input[i + 1] = high byte

    So 9c 85 corresponds to 0x859c.

  3. Block-based processing The loop advances by i += 2, so the algorithm operates on 2-byte blocks. Each block depends only on:

    • its two input bytes

    • the previous state (v3)

    This makes complexity linear, not exponential over the whole flag.


Exploitation

From the loop:

Rewriting:

So for each 2-byte output block (v3_new), we brute-force a and b.

Since:

That’s only:

Completely feasible.

The important detail in Python:

Why & 0xFFFF matters

C automatically truncates __int16 values to 16 bits.

Python integers do not overflow.

Without:

the state keeps growing beyond 16 bits and the reconstruction fails after the first block.

This truncation is absolutely essential.


Python Bruteforce Script


Key Takeaways

  • The write is little-endian.

  • The search space is only 65536 per block, which is trivial.

  • Correctly updating prev_x is mandatory or the chain breaks.

Everything else (odd-length handling, formatting, printing) is minor compared to these core insights.

made by k0d

Last updated