Привет, Хабр!
В прошлой статье мы разбирались, как можно спрятать данные внутри файлов Microsoft Office, причем не только в текстовых документах (.docx), но и в таблицах (.xlsx) и презентациях (.pptx), используя стандартный механизм Custom XML Parts. Сегодня мы продолжим исследовать мир офисной стеганографии и обратим свой взор на открытый и популярный формат OpenDocument Format (ODF), на котором работают LibreOffice и Apache OpenOffice. Этот метод так же универсален и применим ко всей линейке форматов: .odt (текстовые документы), .ods (таблицы) и .odp (презентации).

Мы рассмотрим, в чем его принципиальное отличие от формата Microsoft, напишем Python-скрипт для встраивания полезной нагрузки и, конечно же, посмотрим на код.
ZIP — всему голова. Снова
Как и современные файлы MS Office, документы OpenDocument по своей сути являются обычными ZIP-архивами. Если вы возьмете любой .odt файл и поменяете его расширение на .zip, вы сможете заглянуть внутрь и увидеть его структуру: набор XML-файлов и папок.
Эта особенность и лежит в основе нашего метода. Мы можем добавить собственный файл внутрь этого архива. Но просто добавить файл недостаточно — пакет ODF содержит специальный «паспорт» или «опись», в которой перечислены все его составные части. Без обновления этой описи документ, скорее всего, будет считаться поврежденным.
Этот ключевой файл — META-INF/manifest.xml.
OpenDocument vs Open XML: Разница в подходе
Здесь и кроется главное идеологическое различие между ODF и OOXML (формат Microsoft) в контексте нашей задачи.
-
В Open XML (
.docx,.xlsx,.pptx) мы действовали «по правилам». Мы создавали специальную XML-часть (customXml/item1.xml), оборачивали наши данные в hex-представление внутри XML-тега и добавляли на нее ссылку в файле связей (_rels/document.xml.rels). Это более структурированный, но и более сложный путь. -
В OpenDocument (
.odt,.ods,.odp) подход гораздо более прямолинейный. Нам не нужно создавать хитрых XML-оберток. Мы можем просто положить наш файл с полезной нагрузкой (например,secret/payload.dat) внутрь архива и затем честно «задекларировать» его в манифесте.
Этот метод проще и позволяет внедрять бинарные данные как есть, без кодирования в текст (вроде hex или base64).
Реализация на Python: шаг за шагом
Давайте разберем код, который реализует этот процесс в файле odf_stego.py.
Встраивание данных (hide_in_odf)
Вот основная функция, которая выполняет всю работу:
# odf_stego.py import zipfile import shutil import os from xml.etree import ElementTree as ET PAYLOAD_FILENAME = 'secret/payload.dat' MANIFEST_PATH = 'META-INF/manifest.xml' MANIFEST_NS = "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" def hide_in_odf(src_odf_path: str, dest_odf_path: str, payload_bytes: bytes): """Распаковывает ODF, добавляет секретный файл, обновляет манифест и запаковывает обратно.""" temp_dir = dest_odf_path + "_temp" if os.path.exists(temp_dir): shutil.rmtree(temp_dir) try: # 1. Распаковываем ODF-контейнер во временную папку with zipfile.ZipFile(src_odf_path, 'r') as odf_zip: odf_zip.extractall(temp_dir) # 2. Создаем и записываем наш секретный файл payload_path = os.path.join(temp_dir, PAYLOAD_FILENAME) os.makedirs(os.path.dirname(payload_path), exist_ok=True) with open(payload_path, 'wb') as f: f.write(payload_bytes) # 3. Обновляем манифест (самая важная часть) manifest_full_path = os.path.join(temp_dir, MANIFEST_PATH) ET.register_namespace('manifest', MANIFEST_NS) tree = ET.parse(manifest_full_path) root = tree.getroot() # Создаем новую запись для нашего файла new_entry = ET.Element(f'{{{MANIFEST_NS}}}file-entry', { f'{{{MANIFEST_NS}}}full-path': PAYLOAD_FILENAME, f'{{{MANIFEST_NS}}}media-type': 'application/octet-stream' }) root.append(new_entry) tree.write(manifest_full_path, encoding='UTF-8', xml_declaration=True) # 4. Запаковываем все обратно в новый ODF-файл shutil.make_archive(dest_odf_path.replace(os.path.splitext(dest_odf_path)[1], ''), 'zip', temp_dir) # Переименовываем .zip в нужное расширение (.odt, .ods и т.д.) if os.path.exists(dest_odf_path): os.remove(dest_odf_path) shutil.move(dest_odf_path.replace(os.path.splitext(dest_odf_path)[1], '.zip'), dest_odf_path) finally: # 5. Очищаем за собой временные файлы if os.path.exists(temp_dir): shutil.rmtree(temp_dir)
Извлечение данных (reveal_from_odf)
Извлечение данных становится тривиальной задачей. Нам даже не нужно парсить XML, если мы знаем точный путь к нашему файлу.
def reveal_from_odf(odf_path: str) -> bytes | None: """Простой метод извлечения: ищет секретный файл по известному пути.""" # ... (код функции, как в предыдущем ответе)
Философия проекта: Зачем всё это?
Прежде чем двигаться дальше, стоит ответить на вопрос: зачем вообще создавать такой инструмент? Цели проекта выходят за рамки простого «спрятать файлик».
-
Исследование и образование. Современные файловые форматы — это сложные и интересные структуры. Разработка такого инструмента заставляет глубоко погрузиться в спецификации OOXML и ODF, понять их внутреннюю логику. Стеганография — это отличный прикладной способ изучить, как устроены файлы, с которыми мы работаем каждый день.
-
Цифровые водяные знаки (Watermarking). Не всегда речь идет о секретности. В документ можно незаметно встроить идентификатор автора, информацию о лицензии или уникальную метку для отслеживания распространения файла. Это помогает защитить интеллектуальную собственность.
-
Целостность данных. Представьте, что у вас есть документ и к нему — файл с ключами, заметками или метаданными. Наш подход позволяет «вшить» эти связанные данные прямо в основной файл, создавая единый, самодостаточный пакет. Это гарантирует, что дополнительная информация не потеряется при передаче.
-
Правдоподобное отрицание. Классическая цель стеганографии. В отличие от очевидно зашифрованного архива (
secret_data.zip.enc), обычный на вид отчет или презентация не вызывают подозрений. Это позволяет скрыть сам факт наличия тайной переписки.
А есть ли аналоги?
Рынок стеганографических программ довольно насыщен, но есть нюанс. Подавляющее большинство утилит (например, знаменитый Steghide) работают с медиаконтейнерами: изображениями, аудио и видео. Ниша офисных документов освоена гораздо слабее.
При поиске аналогов можно найти:
-
Академические проекты и PoC. Существует множество исследований и скриптов на GitHub, которые демонстрируют возможность сокрытия данных в офисных файлах. Однако чаще всего это узкоспециализированные консольные утилиты, поддерживающие один конкретный формат (обычно
.docx) и один метод. -
Специализированный коммерческий софт. Некоторые решения для DLP (Data Loss Prevention) и форензики умеют анализировать офисные файлы на предмет скрытых данных, но редко предоставляют функционал для их простого создания.
Что касается комплексных решений с графическим интерфейсом, которые бы удобно поддерживали и Open XML, и OpenDocument форматы, то их найти практически не удалось. Обычно поддержка ограничивается чем-то одним, либо вовсе отсутствует.
Это и стало одной из ключевых причин для создания нашего инструмента «ChameleonLab» — дать пользователю простой и универсальный способ работать с самыми популярными офисными форматами в одном месте.
Интеграция и будущие планы
В нашем приложении «Хамелеон» этот функционал будет интегрирован в основной рабочий процесс, позволяя пользователю выбирать между разными типами контейнеров.
Интерфейс выбора контейнера и файла для встраивания в приложении.
Поддержка ODF-документов делает наш инструмент более универсальным, так как позволяет работать с файлами, созданными в популярных бесплатных офисных пакетах.
И самое главное: в будущих сборках нашего приложения мы планируем добавить полноценную поддержку этого метода для работы с ODF-документами, предоставляя пользователям еще больше гибкости.
Заключение
Мы рассмотрели простой, но эффективный метод сокрытия данных в файлах OpenDocument. В отличие от более сложного подхода, необходимого для .docx, здесь мы работаем с архивом напрямую, что упрощает код и убирает необходимость в дополнительном кодировании данных.
Оба метода — и для OOXML, и для ODF — имеют право на жизнь и показывают, какими гибкими могут быть современные офисные форматы, если заглянуть к ним «под капот».
Где скачать и следить за проектом?
Последнюю версию программы «Steganographia» от ChameleonLab для Windows и macOS можно скачать на нашем официальном сайте.
На данный момент мы активно работаем над подготовкой сборки для пользователей Linux, которая появится в ближайшее время.
А чтобы быть в курсе обновлений, обсуждать новые функции и общаться с единомышленниками, присоединяйтесь к нашему Telegram-каналу.
Спасибо за внимание!
ссылка на оригинал статьи https://habr.com/ru/articles/944334/
Добавить комментарий