← Back to Writeups
CUSTOMMediumMisc

Киноман

XESXOR9/10/20263 min read
#misc#custom#medium#decimal_ascii_decoding#embedded_image_extraction#episode_number_mapping#visual_symbol_identification

Киноман

Platform: hackerlab | Category: Misc | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2025-12-26 | Status: Solved Techniques: decimal_ascii_decoding, embedded_image_extraction, episode_number_mapping, visual_symbol_identification

Summary

Task: a ZIP archive contained an image-only PDF filled with repeating silver sigils on black squares. Solution: extract the embedded images, identify them as The Witcher episode intro logos, map each symbol to its episode number, and decode symbol pairs as ASCII decimal.

Киноман — hackerlab

Description

Киноман

The archive contained a PDF with three pages of repeated silver-on-black symbols. The goal was to understand what the symbols represented and turn that pattern into the flag.

Summary

This was a symbol-identification and decoding challenge. After confirming the PDF itself did not hide extra data, the correct path was to extract the embedded images, recognize the symbols as The Witcher episode intro logos, map each one to an episode number, and decode pairs of symbols as ASCII decimal values. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Reconnaissance

Initial file/PDF forensics did not reveal any hidden payloads. The PDF was image-only, so there was no useful text layer, metadata trick, or embedded document to recover.

The next step was to extract all images from the PDF. That produced 52 total images, but many were duplicates. After deduplication there were only 13 unique symbols, which strongly suggested a substitution system rather than pure decoration.

Identification of Symbols

The unique images matched the stylized intro logos used in Netflix's The Witcher episodes, mostly from seasons 1 and 2. The important insight was that each symbol should be treated not as a letter, but as an episode identifier. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The numbering that makes the decoding work is the overall episode index across the show:

  • season 1 episode 1-8 → 1-8
  • season 2 episode 1-8 → 9-16

With that mapping, the symbols used at the start of the message decode as:

  • A B → 67 → C
  • B C → 79 → O
  • A D → 68 → D
  • A C → 69 → E
  • A A → 66 → B
  • D C → 89 → Y

So the plaintext clearly starts with CODEBY{.

Decoding Method

Each row contains 4 symbols. Read them as two pairs:

  • symbols 1-2 form one decimal ASCII code
  • symbols 3-4 form the next decimal ASCII code ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

For example, if two adjacent symbols map to episode numbers 6 and 7, concatenate them into 67, then interpret that as ASCII C.

Repeating this pairwise decimal-ASCII process across all rows reconstructs the full flag.

python
#!/usr/bin/env python3

episode_map = {
    "A": 6,
    "B": 7,
    "C": 9,
    "D": 8,
    # add the remaining symbol->episode mappings after identification
}

def decode_pairs(pairs):
    out = []
    for left, right in pairs:
        value = int(f"{episode_map[left]}{episode_map[right]}")
        out.append(chr(value))
    return "".join(out)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

print(decode_pairs([
    ("A", "B"),
    ("B", "C"),
    ("A", "D"),
    ("A", "C"),
    ("A", "A"),
    ("D", "C"),
]))
# CODEBY

Final Flag

text
CODEBY{REDACTED}

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