← Back to Writeups
CUSTOMEasySteganography

Шепчущий Свиток Клодa (Whispering Scroll of Claude)

XESXOR9/2/20264 min read
#steganography#custom#easy#binary_encoding#zero_width_unicode_steganograp#linux

Шепчущий Свиток Клодa (Whispering Scroll of Claude)

Platform: caplag | Category: Steganography | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-02-22 | Status: Solved Techniques: binary_encoding, zero_width_unicode_steganography

Summary

Task: find a hidden message in a UTF-8 text file with suspiciously large file size. Solution: extract zero-width Unicode characters (ZWNJ=0, ZWJ=1) from the text, decode 280 bits as 35 ASCII bytes to reveal the flag.

Шепчущий Свиток Клодa (Whispering Scroll of Claude) — caplag

Description

В эпической саге "Герои Кодекса" мудрый маг Claude, сражаясь с генеративным воином GPT в лесах CodeRealm, оставил шепчущий свиток. В нём скрыто тайное послание — заклинание триумфа. Разгадайте секрет, чтобы обрести флаг!

File: scroll.txt — UTF-8 text file, 2037 bytes, containing a Russian-language narrative.

Hint Decoding

Phrase in descriptionMeaning
"шепчущий свиток" (whispering scroll)Data hidden in the text file — invisible to the eye
"скрытые частоты unicode-эфира"Zero-width Unicode characters embedded in the text
"тайное послание" (secret message)Binary-encoded flag using invisible characters
"набросил вуаль невидимости"Invisible (zero-width) characters used as the hiding medium
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The critical in-text hint: "Только те, кто настроен на скрытые частоты unicode-эфира, могли разобрать секретное сообщение мага" — directly points to Unicode steganography.

Analysis

Step 1 — Initial recon

The file appears to be a plain Russian text about a battle between the mage Claude and the generative warrior GPT. However, the file size (2037 bytes) is suspiciously large for just 4 short paragraphs of visible text.

bash
file scroll.txt
# scroll.txt: UTF-8 Unicode text

wc -c scroll.txt
# 2037 scroll.txt

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 2 — Hex dump reveals invisible characters

Examining the hex dump of the file reveals a large block of repeating byte sequences at the end:

bash
xxd scroll.txt | tail -20

The output shows a massive block of bytes e2 80 8c and e2 80 8d — these are the UTF-8 encodings of:

  • U+200C — ZWNJ (Zero Width Non-Joiner) → e2 80 8c
  • U+200D — ZWJ (Zero Width Joiner) → e2 80 8d

These are invisible Unicode characters — they have zero visual width and render as nothing in text editors and terminals. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 3 — Binary encoding identification

Counting the zero-width characters reveals exactly 280 of them, using exactly 2 unique types. This is a classic binary encoding:

  • 2 character types → 1 bit per character
  • 280 characters ÷ 8 bits/byte = 35 bytes — a perfect match for a flag string like caplag{...}

Step 4 — Decode

Mapping: ZWNJ (U+200C) = 0, ZWJ (U+200D) = 1

Solution

python
#!/usr/bin/env python3
"""
Decode zero-width Unicode steganography from scroll.txt.
ZWNJ (U+200C) = bit 0, ZWJ (U+200D) = bit 1.
"""
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

with open('scroll.txt', 'r', encoding='utf-8') as f:
    content = f.read()

# Extract zero-width characters
zw_chars = [c for c in content if c in ('\u200c', '\u200d')]
print(f"Found {len(zw_chars)} zero-width characters")
print(f"Expected bytes: {len(zw_chars) // 8}")

# ZWNJ (U+200C) = 0, ZWJ (U+200D) = 1
bits = ''.join('0' if c == '\u200c' else '1' for c in zw_chars)

# Convert bits to ASCII bytes
result = ''
for i in range(0, len(bits) - 7, 8):
    byte = bits[i:i+8]
    result += chr(int(byte, 2))
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

print(f"Flag: {result}")

Output:

Found 280 zero-width characters
Expected bytes: 35
Flag: caplag{REDACTED}

Key Technique

Zero-Width Unicode Character Steganography — invisible Unicode characters (ZWNJ, ZWJ, zero-width space, etc.) are embedded in normal text to encode a hidden binary message. Each character type represents a bit (0 or 1), and groups of 8 bits decode to ASCII characters.

When to suspect this technique:

  • Text file challenge where the visible content seems normal but file size is too large
  • Description mentions "hidden", "invisible", "unicode", or "frequencies"
  • Hex dump shows repeating e2 80 8c / e2 80 8d / e2 80 8b byte patterns
  • Copy-pasting text produces unexpected behavior or extra whitespace
  • wc -m (character count) is much larger than visible character count ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Common zero-width characters used:

CharacterCode PointUTF-8 BytesName
ZWNJU+200Ce2 80 8cZero Width Non-Joiner
ZWJU+200De2 80 8dZero Width Joiner
ZWSPU+200Be2 80 8bZero Width Space
WJU+2060e2 81 a0Word Joiner
FEFFU+FEFFef bb bfZero Width No-Break Space (BOM)

Detection one-liner:

bash
xxd scroll.txt | grep -c "e2 80 8[bcd]"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍