← Back to Writeups
CUSTOMMediumSteganography

Rabbit Hole

XESXOR9/2/20264 min read
#steganography#custom#medium#file-timestamp-ordering-for-se#morse-code-encoding-with-unico#pdf-metadata-steganography-(pr#unicode-steganography-using-vi#linux

Rabbit Hole

Platform: hackerlab | Category: Steganography | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2025-12-22 | Status: Solved Techniques: File timestamp ordering for sequence recovery, Morse code encoding with Unicode symbols, PDF metadata steganography (Producer field), Unicode steganography using visually similar characters

Summary

Task: Archive with 10 PDF files with emoji names. Solution: Extract Producer field from PDF metadata, decode hex to Unicode symbols (U+2022/U+2024), interpret as Morse code, order by modification year timestamps.

Rabbit Hole - hackerlab.pro

Description

"Иногда рэббит холл очевиден" (Sometimes rabbit hole is obvious)

Archive task.zip contains 10 PDF files with emoji names.

Analysis

1. Archive Contents

task.zip
├── 😃.pdf
├── 😁.pdf
├── 😅.pdf
├── 😂.pdf
├── 🙂.pdf
├── 🫠.pdf
├── 😊.pdf
├── 🥰.pdf
├── 😘.pdf
└── 🤔.pdf

2. Determining File Order

Each PDF has a different modification year (2053-2062):

bash
exiftool -ModifyDate *.pdf
ГодФайл
2053😃
2054😁
2055😅
2056😂
2057🙂
2058🫠
2059😊
2060🥰
2061😘
2062🤔
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

3. Hidden Data in Producer

The /Producer field in PDF metadata contains hex-encoded Unicode:

bash
exiftool -Producer *.pdf

Data structure:

  • feff — BOM (Byte Order Mark), start marker
  • 2022 — U+2022 (BULLET •)
  • 2024 — U+2024 (ONE DOT LEADER ․)

4. Extracted Data

ГодProducer (hex)Unicode символы
2053feff2022•
2054feff2024202420242024․․․․
2055feff2022202420242022•․․•
2056feff2024202420222024․․•․
2057feff20222022202220222022•••••
2058feff202420222024․•․
2059feff202220222024••․
2060feff20242024202420242022․․․․•
2061feff20222022••
2062feff2024․
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

5. Interpretation as Morse Code

Unicode symbols are visually similar to dots and dashes:

  • U+2022 (BULLET •) → dash (-)
  • U+2024 (ONE DOT LEADER ․) → dot (.)
ГодMorseБуква
2053-T
2054....H
2055-..-X
2056..-.F
2057-----0
2058.-.R
2059--.G
2060....-4
2061--M
2062.E

Result: THXF0RG4ME (leet speak for "Thanks for game") ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

python
#!/usr/bin/env python3
"""
Rabbit Hole - PDF Metadata Morse Steganography
"""

import subprocess
import re

# Morse code dictionary
MORSE_TO_CHAR = {
    '.-': 'A', '-...': 'B', '-.-.': 'C', '-..': 'D', '.': 'E',
    '..-.': 'F', '--.': 'G', '....': 'H', '..': 'I', '.---': 'J',
    '-.-': 'K', '.-..': 'L', '--': 'M', '-.': 'N', '---': 'O',
    '.--.': 'P', '--.-': 'Q', '.-.': 'R', '...': 'S', '-': 'T',
    '..-': 'U', '...-': 'V', '.--': 'W', '-..-': 'X', '-.--': 'Y',
    '--..': 'Z', '-----': '0', '.----': '1', '..---': '2',
    '...--': '3', '....-': '4', '.....': '5', '-....': '6',
    '--...': '7', '---..': '8', '----.': '9'
}
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def get_pdf_metadata(pdf_file):
    """Extract ModifyDate and Producer from PDF"""
    result = subprocess.run(
        ['exiftool', '-ModifyDate', '-Producer', pdf_file],
        capture_output=True, text=True
    )
    
    year = None
    producer = None
    
    for line in result.stdout.split('\n'):
        if 'Modify Date' in line:
            match = re.search(r'(\d{4}):', line)
            if match:
                year = int(match.group(1))
        elif 'Producer' in line:
            producer = line.split(':', 1)[1].strip()
    
    return year, producer
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def hex_to_morse(hex_producer):
    """Convert hex-encoded Producer to Morse code"""
    # Remove 'feff' BOM prefix
    hex_data = hex_producer.lower().replace('feff', '')
    
    morse = ''
    # Process 4 hex chars at a time (one Unicode codepoint)
    for i in range(0, len(hex_data), 4):
        codepoint = hex_data[i:i+4]
        if codepoint == '2022':  # BULLET
            morse += '-'
        elif codepoint == '2024':  # ONE DOT LEADER
            morse += '.'
    
    return morse

def solve():
    import glob
    
    # Get all PDF files
    pdf_files = glob.glob('*.pdf')
    
    # Extract metadata
    data = []
    for pdf in pdf_files:
        year, producer = get_pdf_metadata(pdf)
        if year and producer:
            data.append((year, pdf, producer))
    
    # Sort by year
    data.sort(key=lambda x: x[0])
    
    # Decode
    flag = ''
    for year, filename, producer in data:
        morse = hex_to_morse(producer)
        char = MORSE_TO_CHAR.get(morse, '?')
        flag += char
        print(f"{year} ({filename}): {producer} -> {morse} -> {char}")
    
    print(f"\nDecoded: {flag}")
    print(f"Flag: CODEBY{{{flag.lower()}}}")
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

if __name__ == '__main__':
    solve()

Notes

  1. Unicode steganography: Using visually similar Unicode characters:

    • U+2022 (•) BULLET vs U+2024 (․) ONE DOT LEADER
    • Both look like dots but have different codepoints
  2. PDF Producer field: Non-standard place for hiding data, usually contains the name of the PDF creation software

  3. Timestamps as key: Years 2053-2062 are clearly unrealistic — this is a hint to use them for sorting

  4. Name "Rabbit Hole": Hint at deep investigation, not the Rabbit cipher ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍