Rabbit Hole
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 read-only • copy allowedexiftool -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 read-only • copy allowedexiftool -Producer *.pdf
Data structure:
feff— BOM (Byte Order Mark), start marker2022— U+2022 (BULLET •)2024— U+2024 (ONE DOT LEADER ․)
4. Extracted Data
| Год | Producer (hex) | Unicode символы |
|---|---|---|
| 2053 | feff2022 | • |
| 2054 | feff2024202420242024 | ․․․․ |
| 2055 | feff2022202420242022 | •․․• |
| 2056 | feff2024202420222024 | ․․•․ |
| 2057 | feff20222022202220222022 | ••••• |
| 2058 | feff202420222024 | ․•․ |
| 2059 | feff202220222024 | ••․ |
| 2060 | feff20242024202420242022 | ․․․․• |
| 2061 | feff20222022 | •• |
| 2062 | feff2024 | ․ |
| |
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 read-only • copy allowed#!/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
-
Unicode steganography: Using visually similar Unicode characters:
- U+2022 (•) BULLET vs U+2024 (․) ONE DOT LEADER
- Both look like dots but have different codepoints
-
PDF Producer field: Non-standard place for hiding data, usually contains the name of the PDF creation software
-
Timestamps as key: Years 2053-2062 are clearly unrealistic — this is a hint to use them for sorting
-
Name "Rabbit Hole": Hint at deep investigation, not the Rabbit cipher