Domino Effect
/ Update
2 min read
The Domino Effect (Crypto) - Findings So Far#
Challenge#
- Name:
The Domino Effect - Service:
nc chals2.apoorvctf.xyz 13337 - Provided file:
domino-challenge.py - Expected flag format:
apoorvctf{...}
Given Source Analysis#
From domino-challenge.py:
-
Secret per connection:
self.secret_message = urandom(16).hex()- This is 16 random bytes represented as 32 hex ASCII chars.
- Effective entropy: 128 bits.
-
Encryption endpoint:
- Returns CBC ciphertext of the secret with random IV:
ct = iv || AES-CBC_k(secret_message)- For this secret length (32 bytes), ciphertext body is 32 bytes (2 blocks).
-
Padding oracle endpoint:
- Decrypts user-provided ciphertext and checks PKCS#7 validity.
- Returns noisy bit:
noisy_response = is_valid ^ (rng.random() > 0.45)
- So the oracle bit is flipped with probability ~0.55.
-
Query budget:
MAX_QUERIES = 10_000- Session exits after hitting budget.
-
Flag check:
checkrequires exact equality withsecret_message.- Wrong guess terminates session immediately.
Remote Verification#
Observed against chals2.apoorvctf.xyz:13337:
- Banner differs slightly from local text but behavior matches challenge flow.
encryptreturns 48-byte total ciphertext (hex length 96):- 16-byte IV + 32-byte CBC ciphertext.
- Invalid ciphertexts fed repeatedly to
unpadshow noisy boolean output roughly centered near expected bias.
Why This Appears Unsolvable As-Is#
The task structure implies noisy padding-oracle recovery of a 32-char hex secret. However:
- Unknown data to recover: 128 bits.
- Oracle noise after best inversion is still high (binary symmetric channel with crossover ~0.45).
- With 10,000 oracle queries, total extractable information is insufficient to reliably identify a full 128-bit random secret.
- Multi-session retries do not help because each new connection generates a fresh random secret.
- Blind forcing
checkis infeasible; only one wrong check is allowed before session termination.
Tested Dead Ends#
- Repeated
unpadsampling on malformed ciphertext to estimate noise profile. - Considering standard CBC padding-oracle byte recovery under noisy majority voting.
- Session reset / repeated connections for aggregation (not useful due to fresh secret each run).
- Input-format edge cases (
JSON/bad ct) do not expose extra leakage.
Current Conclusion#
Based on provided code and observed remote behavior, this challenge is likely misconfigured or buggy in deployment parameters (noise/limit/secret-size balance).
Most plausible issue: the noise threshold line
noisy_response = is_valid ^ (rng.random() > 0.45)pythonmay be unintended for the chosen secret length and query budget.
Suggested Organizer Query#
Ask whether one of these differs on the intended instance:
- Noise threshold (e.g.,
> 0.55instead of> 0.45), - Query limit (
MAX_QUERIES), - Secret generation/length,
- Remote source parity with the distributed file.
Repro Notes#
Minimal interaction pattern:
{"option":"encrypt"}
{"option":"unpad","ct":"<hex>"}
{"option":"check","message":"<candidate>"}jsonAny wrong check ends the session.
Domino Effect
https://nahil.xyz/vault/writeups/apoorvctf2026/cryptography/domino-effect/
Author Nahil Rasheed
Published at March 24, 2026
Copyright
CC BY-NC-SA 4.0
Disclaimer This content is provided strictly for educational purposes only.