← Back to Writeups
CUSTOMMediumWeb

Miss-Input

XESXOR9/10/20264 min read
#web#custom#medium#known_plaintext_attack#constraint_propagation#pattern_recognition#xor_key_recovery

Miss-Input

Platform: scarlet | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-01-11 | Status: Solved Techniques: known_plaintext_attack, constraint_propagation, pattern_recognition, xor_key_recovery

Summary

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.

Miss-Input - Scarlet CTF

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.wasm file (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

  1. Flag format: RUSEC{...} - we know positions 0-5 and position 34
  2. Key derivation from known plaintext:
    • XORing encrypted bytes with "RUSEC{" gives key prefix: M151NP (leet for "MISINP")
    • Position 34 must decrypt to "}"

Key Length Discovery

Testing key length constraint: key[34 % key_length] must produce "}" ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  • Key length 12 satisfies this: 34 % 12 = 10, so key[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:

PositionKey charDecrypted
6, 18, 30M?
7, 19, 311?
8, 20, 325?
9, 21, 331?
10, 22, 34N?
11, 23P?
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
encrypted = 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
#!/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

  1. Known-plaintext attack - Using "RUSEC{" prefix and "}" suffix to derive key characters
  2. Constraint propagation - Key length constraint from flag ending position
  3. Pattern recognition - Identifying "CALM_DOWN" and "MISINPUT" in partial decryption
  4. 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 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍