Morse Excel (Отчёт бухгалтера)
Morse Excel (Отчёт бухгалтера)
Platform: hackerlab.pro | Category: Steganography | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2025-12-22 | Status: Solved Techniques: XLSX structure analysis (ZIP with XML), Cell style/formatting analysis, Morse code via font formatting (italic=dot, bold=dash)
Summary
Given file task.xlsx — an Excel document with a financial report.
Morse Excel (Отчёт бухгалтера) — hackerlab.pro
Description
Бухгалтер мне прислал следующий отчёт. Насколько мне известно у нашей компании совсем другие цифры, возможно, он хотел мне сказать что-то что нельзя написать открыто?
Given file task.xlsx — an Excel document with a financial report.
Analysis
1. XLSX Structure
XLSX is a ZIP archive with XML files inside:
bash read-only • copy allowedunzip task.xlsx -d xlsx_contents/
Structure:
xlsx_contents/
├── [Content_Types].xml
├── _rels/
├── docProps/
└── xl/
├── worksheets/sheet1.xml # Cell data
├── styles.xml # Formatting styles
├── sharedStrings.xml # Text values
└── workbook.xml
2. Analyzing sheet1.xml
In the first row (row 1), multiple cells from A1 to DX1 were found with different style attributes (s):
xml read-only • copy allowed<c r="A1" s="2" t="s"><v>0</v></c> <c r="B1" s="3"/> <c r="C1" s="4"/> <c r="D1" s="3"/> <c r="E1" s="5"/> <!-- empty style = separator --> <c r="F1" s="4"/> ... <c r="Z1" s="6"/> <!-- underlined = word separator -->
3. Analyzing styles.xml
Style decoding through <fonts> and <cellXfs> analysis:
| Style ID | fontId | Description | Morse value |
|---|---|---|---|
| 2 | 4 | Normal with fill | - (dash) |
| 3 | 5 | Italic (<i val="true"/>) | . (dot) |
| 4 | 6 | Bold (<b val="true"/>) | - (dash) |
| 5 | 0 | Normal | (letter separator) |
| 6 | 7 | Underlined (<u val="single"/>) | / (word separator) |
| |
4. Encoding Pattern
Steganography via Excel cell formatting:
- Italic = dot (.)
- Bold = dash (-)
- Normal font = separator between letters
- Underlined = separator between words (/)
Solution
Extraction Script
python read-only • copy allowed#!/usr/bin/env python3 import zipfile import xml.etree.ElementTree as ET 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', '..--.-': '_' } # Extract and parse XLSX with zipfile.ZipFile('task.xlsx', 'r') as z: # Parse styles styles_xml = z.read('xl/styles.xml').decode('utf-8') # Parse sheet sheet_xml = z.read('xl/worksheets/sheet1.xml').decode('utf-8') # Extract cell styles from row 1 # Pattern: <c r="XX1" s="N"/> or <c r="XX1" s="N" t="s"> cells = re.findall(r'<c r="([A-Z]+)1"(?: s="(\d+)")?', sheet_xml) # Style mapping based on analysis # Style 2, 4 = dash (-), Style 3 = dot (.), Style 5 = letter sep, Style 6 = word sep morse_code = [] current_letter = [] for col, style in cells: style = int(style) if style else 5 # default to separator if style in [2, 4]: # bold or filled = dash current_letter.append('-') elif style == 3: # italic = dot current_letter.append('.') elif style == 5: # normal = letter separator if current_letter: morse_code.append(''.join(current_letter)) current_letter = [] elif style == 6: # underline = word separator if current_letter: morse_code.append(''.join(current_letter)) current_letter = [] morse_code.append('/') if current_letter: morse_code.append(''.join(current_letter)) # Decode Morse morse_string = ' '.join(morse_code) print(f"Morse: {morse_string}") result = [] for code in morse_code: if code == '/': result.append(' ') elif code in MORSE_TO_CHAR: result.append(MORSE_TO_CHAR[code]) else: result.append(f'[{code}]') decoded = ''.join(result) print(f"Decoded: {decoded}")
Extracted Morse Code
-.-. --- -.. . -... -.-- / -.. ...-- ...- ...-- .-.. --- .--. . .-. ... ..--.- .-.. ----- ...- ...-- ..--.- -- ----- .-. ... .
Decoding
| Morse | Symbol |
|---|---|
-.-. --- -.. . -... -.-- | CODEBY |
/ | (space) |
-.. | D |
...-- | 3 |
...- | V |
...-- | 3 |
.-.. | L |
--- | O |
.--. | P |
. | E |
.-. | R |
... | S |
..--.- | _ |
.-.. | L |
----- | 0 |
...- | V |
...-- | 3 |
..--.- | _ |
-- | M |
----- | 0 |
.-. | R |
... | S |
. | E |
Result: CODEBY REDACTED
The first word "CODEBY" is the flag format, the flag content is: REDACTED
Alternative Approaches
- Visual analysis in Excel: Open the file and look at cell formatting
- LibreOffice Calc: May display styles more clearly
- Python openpyxl: Library for working with XLSX, can extract styles programmatically
Related Techniques
- Font-based steganography (as in RTF documents)
- Cell color steganography (cell colors instead of fonts)
- Hidden rows/columns in spreadsheets
- Comment steganography in Office documents