Miss-Input
Miss-Input
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: known_plaintext_attack, constraint_propagation, pattern_recognition, xor_key_recovery
Summary
Walkthrough of the CUSTOM Web Miss-Input. The challenge presents a "TACTICAL INPUT SYSTEM" web page with an input field that has a "misinput" effect - when typing, random characters are inserted. There's a downloadable WASM file (`challenge.w
Description
"IT'S A MISINPUT! YOU CALM DOWN! YOU CALM THE F DOWN!"
The challenge presents a "TACTICAL INPUT SYSTEM" web page with an input field that has a "misinput" effect - when typing, random characters are inserted. There's a downloadable WASM file (challenge.wasm) and a YouTube video reference to Phil Hellmuth's famous poker outburst.
Analysis
Initial Reconnaissance
The challenge is a Next.js web application with:
- A themed input system with intentional "misinput" behavior
- A downloadable
challenge.wasmfile (134 bytes) containing XOR functions - JavaScript code with an encrypted hex string and decryption function
window.__tactical_support_v2(key)
Encrypted Data
From the JavaScript source:
Encrypted hex: 1f6466740d2b0c070a187370017c6a757e071b686e70051b0c6e78007b611b670a704d
Length: 35 bytes
The decryption is simple XOR with a repeating key.
Known Constraints
- Flag format:
RUSEC{...}- we know positions 0-5 and position 34 - Key derivation from known plaintext:
- XORing encrypted bytes with "RUSEC{" gives key prefix:
M151NP(leet for "MISINP") - Position 34 must decrypt to "}"
- XORing encrypted bytes with "RUSEC{" gives key prefix:
Key Length Discovery
Testing key length constraint: key[34 % key_length] must produce "}"
- Key length 12 satisfies this:
34 % 12 = 10, sokey[10]must XOR to give "}" - Key format so far:
M151NP????0?
Constraint Propagation
With key length 12, certain positions in the flag content are determined by known key characters:
| Position | Key char | Decrypted |
|---|---|---|
| 6, 18, 30 | M | ? |
| 7, 19, 31 | 1 | ? |
| 8, 20, 32 | 5 | ? |
| 9, 21, 33 | 1 | ? |
| 10, 22, 34 | N | ? |
| 11, 23 | P | ? |
| 0, 12, 24 | ? | R, ?, ? |
| ... | ... | ... |
The partially decrypted content revealed: ????C?LM_D0W????5?A_M151????
Pattern Recognition
The fixed parts strongly suggested:
- "CALM_D0WN" - matching the challenge theme
- "M151" - leet for "MISI" (part of MISINPUT)
Target plaintext: REDACTED
This translates to: "YOU CALM DOWN, IT'S A MISINPUT!" - directly referencing the Phil Hellmuth quote!
Key Recovery
Working backwards from the target plaintext to derive remaining key characters:
python read-only • copy allowedencrypted = bytes.fromhex("1f6466740d2b0c070a187370017c6a757e071b686e70051b0c6e78007b611b670a704d") target = "RUSEC{REDACTED}" # Derive key from known plaintext key_chars = {} for i, (e, p) in enumerate(zip(encrypted, target.encode())): key_chars[i % 12] = chr(e ^ p) # Reconstruct key key = ''.join(key_chars[i] for i in range(12)) print(key) # M151NPU7_G0D
Final Key: M151NPU7_G0D (leet for "MISINPUT GOD")
Solution
python read-only • copy allowed#!/usr/bin/env python3 """ Miss-Input - Scarlet CTF XOR decryption with known-plaintext attack """ def xor_decrypt(encrypted_hex: str, key: str) -> str: """Decrypt XOR-encrypted hex string with repeating key""" encrypted = bytes.fromhex(encrypted_hex) key_bytes = key.encode() decrypted = bytes([ encrypted[i] ^ key_bytes[i % len(key_bytes)] for i in range(len(encrypted)) ]) return decrypted.decode('ascii') def derive_key_from_known_plaintext(encrypted_hex: str, known_prefix: str, known_suffix: str) -> str: """ Derive XOR key using known plaintext attack. Uses flag format RUSEC{...} to recover key characters. """ encrypted = bytes.fromhex(encrypted_hex) # Get key characters from prefix "RUSEC{" key_chars = {} for i, (e, p) in enumerate(zip(encrypted, known_prefix.encode())): key_chars[i] = chr(e ^ p) # Key prefix is "M151NP" (leet for MISINP) print(f"Key prefix from 'RUSEC{{': {''.join(key_chars[i] for i in range(6))}") # Find key length using suffix constraint # Position 34 must decrypt to "}" suffix_pos = len(encrypted) - 1 suffix_byte = encrypted[suffix_pos] for key_len in range(6, 20): key_pos = suffix_pos % key_len if key_pos < len(key_chars): expected = ord(known_suffix) ^ suffix_byte if key_chars[key_pos] == chr(expected): print(f"Key length {key_len} satisfies suffix constraint") return key_len return None def main(): # Encrypted data from challenge JavaScript encrypted_hex = "1f6466740d2b0c070a187370017c6a757e071b686e70051b0c6e78007b611b670a704d" # The key derived through constraint analysis # M151NPU7_G0D = "MISINPUT GOD" in leet speak key = "M151NPU7_G0D" # Decrypt flag = xor_decrypt(encrypted_hex, key) print(f"Flag: {flag}") # Verify assert flag == "RUSEC{REDACTED}" print("Verification: OK") # Decode the leet speak print("\nFlag meaning:") print("REDACTED") print("= YOU CALM DOWN IT'S A MISINPUT") print("(Reference to Phil Hellmuth's famous poker outburst)") if __name__ == "__main__": main()
Execution
$ python3 solve.py
Key prefix from 'RUSEC{': M151NP
Flag: RUSEC{REDACTED}
Verification: OK
Flag meaning:
REDACTED
= YOU CALM DOWN IT'S A MISINPUT
(Reference to Phil Hellmuth's famous poker outburst)
Key Techniques
- Known-plaintext attack - Using "RUSEC{" prefix and "}" suffix to derive key characters
- Constraint propagation - Key length constraint from flag ending position
- Pattern recognition - Identifying "CALM_DOWN" and "MISINPUT" in partial decryption
- Leet speak interpretation:
- Y0U = YOU
- C4LM = CALM
- D0WN = DOWN
- 175 = ITS
- M151NPU7 = MISINPUT
References
- Phil Hellmuth "It's a misinput" poker clip
- XOR cipher known-plaintext attack
- WebAssembly reverse engineering
Files
challenge.wasm- WebAssembly module with XOR functions and debug section hints- Main JS chunk containing encrypted string and decryption function
Key Takeaways / Lessons
- Mastering known_plaintext_attack, constraint_propagation, pattern_recognition, xor_key_recovery was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-01-11 • CUSTOM • Miss-Input • Difficulty: Medium