cybersecurity · advanced · ~15 min · safe pentest lab

Spot the ECB Fingerprint

Recognise the ECB-mode ciphertext fingerprint (repeated plaintext -> repeated ciphertext blocks) and write a bounds-safe detector that validates attacker-controlled length and block-size arguments before indexing, denying malformed input by default.

Challenge

The problem

AES in ECB mode encrypts every plaintext block independently, so identical plaintext blocks always produce identical ciphertext blocks. That determinism is a leak: an attacker who can see the ciphertext learns which plaintext regions repeat (the classic "ECB penguin"). During a defensive assessment you want a detector that flags this fingerprint in captured ciphertext so you can tell a developer their crypto is broken.

Asset: a fixed buffer of captured ciphertext baked into the test harness. Threat: confidentiality loss from block-level plaintext structure leaking through ECB. Your detector only reads that in-memory array — never a live target, socket, or file.

Your task

Implement has_ecb_repeats(ct, n, block). Return 1 if any two whole block-sized chunks of ct are byte-for-byte identical, otherwise 0.

The dangerous, insecure assumption to avoid is trusting the caller's sizes. You must deny by default: reject block == 0 and a NULL pointer, and only ever read bytes inside [0, (n / block) * block). A trailing partial block (fewer than block bytes) is ignored, never compared.

Edge cases

  • block == 0 → return 0 (never divide or index by it).
  • ct == NULL → return 0.
  • fewer than two whole blocks (n / block < 2) → return 0.
  • a partial trailing block must not be read past n.

Example

has_ecb_repeats(repeat, 16, 4)   -> 1   /* blocks 0 and 2 are identical */
has_ecb_repeats(distinct, 16, 4) -> 0   /* every block differs */

Input format

A pointer ct to n bytes of ciphertext, and a chunk size block. All three are supplied by the (untrusted) caller; sizes may be zero or larger than the buffer's usable region.

Output format

Return int 1 if at least two whole block-sized chunks of ct are identical, else 0. Invalid inputs (block==0, NULL) return 0.

Constraints

ct is ciphertext buffer of n bytes; block is cipher block size.

Starter code

int has_ecb_repeats(const unsigned char *ct, size_t n, size_t block)
{
    /* TODO: detect two identical `block`-sized chunks in ct.
       This insecure stub trusts the input and reports nothing. */
    (void)ct; (void)n; (void)block;
    return -1;
}

Common mistakes

Division by zero when block is 0 or reading partial trailing blocks.

Edge cases to handle

ct == NULL, block == 0, n < block * 2 (cannot have repeats).

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.