Главная / Блог / Стеганография в CTF: чек-лист и инструменты

13 мин.00

Стеганография в CTF: чек-лист и инструменты

Стеганография в CTF: чек-лист и инструменты

На одном из CTF задание из категории Stego казалось тривиальным: JPEG-картинка с текстом на немецком языке. Тридцать минут ушло на steghide, stegsolve, strings — ноль результатов. Флаг был в ZIP-архиве, склеенном с концом JPEG-файла, причём первый байт magic-сигнатуры ZIP 50 4B 03 04 оказался намеренно заменён с 0x50 на 0xFF, превратив начало в FF 4B 03 04. binwalk находил конец архива, но не начало. Задача решилась за минуту — один байт в hex-редакторе, unzip, готово. Этот кейс (подробно разобранный в writeup на dominicbreuker.com) показывает главное: стего-таски решаются не перебором инструментов, а системным чек-листом, где каждый шаг сужает область поиска.

Системный чек-лист: порядок анализа любого стего-таска

Русскоязычные гайды по стеганографии в CTF обычно дают список утилит: «вот steghide, вот binwalk, вот exiftool». Проблема в том, что новичок не понимает порядок запуска и момент перехода к следующему инструменту. Вот порядок, который я использую сам.

Шаг 1 — определение реального типа файла. Расширение .png в задании не гарантирует PNG. Команда file mystery.png покажет реальный формат по magic bytes. Если file возвращает «JPEG image data» при расширении .png — уже подсказка: автор задания маскирует формат.

Шаг 2 — поиск текстовых строк. strings mystery.png | grep -iE "flag|ctf|key" — грубый, но неожиданно эффективный фильтр. Иногда флаг лежит прямо в бинарных данных открытым текстом. Для фильтрации мусора полезен флаг длины: strings -n 10 mystery.png показывает только строки от десяти символов.

Шаг 3 — метаданные. exiftool mystery.png извлекает EXIF, IPTC, XMP и прочие метаполя. В CTF флаги прячут в Comment, Artist, Copyright, а GPS-координаты дают подсказку для геолокационных тасков.

Шаг 4 — поиск вложенных файлов. binwalk mystery.png сканирует файл на сигнатуры других форматов: ZIP, RAR, gzip, PDF, ELF. Найденное вложение извлекается через binwalk -e mystery.png в отдельную директорию.

Шаг 5 — LSB-анализ. Для PNG и BMP — zsteg mystery.png проверяет младшие биты всех каналов. Визуальный анализ битовых плоскостей — через Stegsolve (Java-приложение с GUI).

Шаг 6 — password-based стеганография. steghide extract -sf mystery.jpg пытается извлечь данные из JPEG или WAV. При наличии пароля — брутфорс через stegseek или stegcracker со словарём rockyou.txt.

Порядок не случаен: каждый следующий шаг дороже по времени. file и strings — секунды. exiftool — секунды. binwalk — секунды. zsteg — секунды. А вот брутфорс steghide с rockyou.txt — часы. Запускать его первым — пустая трата времени на CTF, где каждая минута на счету.

Exiftool: метаданные изображений как первый рубеж анализа

exiftool — рабочая лошадка для чтения метаданных из файлов практически любого формата. В forensics CTF заданиях он делает две вещи: находит флаг, спрятанный в метаполях, и даёт подсказки для дальнейшего анализа.

Расширенный вызов exiftool -v2 target.jpg включает вывод всех тегов, включая нестандартные. В CTF данные прячут в полях, которые не отображаются в обычном просмотрщике:

  • Comment / UserComment — текстовые поля, идеальные для строки-флага
  • XMP-dc:Description — часть XMP-метаданных, которую новички систематически пропускают
  • GPS Position — координаты в формате 50 deg 27' 4.68" N, 30 deg 31' 24.12" E (для десятичного формата: exiftool -c '%.6f' target.jpg; вбить в Google Maps — получить название города-флага)
  • Thumbnail Image — встроенная миниатюра может содержать совершенно другую картинку

Нюанс, на котором спотыкаются многие: PNG формально не поддерживает EXIF в классическом понимании (в отличие от JPEG), но хранит метаданные в текстовых чанках — tEXt, zTXt, iTXt. exiftool читает и их. Если Windows через стандартные «Свойства» показывает пустые поля для PNG — это не значит, что метаданных нет. На root-me.org есть классическая задача уровня 5 баллов, где GPS-координаты из метаданных PNG ведут к городу-флагу, а Windows-свойства файла при этом выглядят пустыми.

Ещё один диагностический приём — анализ несоответствий. Если exiftool показывает Software: Adobe Photoshop для файла, который по легенде задания «снят на телефон» — это маркер модификации. Аномальный размер тоже информативен: PNG 100×100 пикселей весом 2 МБ почти наверняка содержит дополнительные скрытые данные в файлах. Картинка 100 на 100 не может столько весить — значит, внутри что-то лишнее.

Binwalk: извлечение файлов из изображений и архивов

binwalk изначально создавался для анализа прошивок IoT-устройств, но прижился в CTF-стеганографии благодаря обширной базе файловых сигнатур. Его задача проста — найти внутри одного файла сигнатуры других форматов.

Базовый сценарий: binwalk target.png сканирует файл и выводит таблицу найденных сигнатур со смещениями. Когда внутри картинки спрятан архив, вывод выглядит примерно так:

DECIMAL    HEXADECIMAL  DESCRIPTION
0          0x0          PNG image, 800 x 600, 8-bit RGBA
1024567    0xFA037      Zip archive data, v2.0 to extract
1025891    0xFA563      End of Zip archive

Обнаруженное вложение извлекается командой binwalk -e target.png в директорию _target.png.extracted/. Для рекурсивного извлечения (архив внутри картинки, внутри архива — другая картинка, матрёшка) есть флаг -M: binwalk -eM target.png проходит все уровни вложенности.

Самый частый приём авторов CTF-заданий — конкатенация файлов. Берётся JPEG и к нему командой cat image.jpg archive.rar > challenge.jpg дописывается RAR-архив. Просмотрщик отображает нормальную картинку (он читает данные до маркера конца JPEG 0xFFD9 и игнорирует остаток), а binwalk видит обе сигнатуры.

Но у binwalk есть слабое место: если magic bytes вложенного файла намеренно повреждены (как в кейсе из вступления — замена 0x50 на 0xFF в первом байте ZIP-сигнатуры), сканер не обнаружит начало архива. В таких случаях binwalk покажет только «End of Zip archive» без начала. Это сигнал для ручного анализа hex-дампа — подробнее в разделе про appended data.

LSB-стеганография: zsteg и stegsolve для извлечения данных из PNG

LSB (Least Significant Bit) — самый распространённый метод стеганографии в CTF-заданиях. Принцип: в каждом пикселе изображения младший бит цветового канала заменяется битом секретного сообщения. Визуальная разница неразличима (изменение яркости на 1 из 255), но данные извлекаются программно.

zsteg — мой первый выбор для обнаружения LSB-стеганографии в PNG и BMP. Установка через gem install zsteg, запуск: zsteg target.png. Утилита автоматически проверяет все комбинации каналов (R, G, B, A) и порядков бит (MSB/LSB). Когда данные найдены, вывод выглядит так:

b1,rgb,lsb,xy  .. text: "flag{hidden_in_plain_sight}"
b1,r,lsb,xy    .. text: "flag{hidden_in_plain_sight}"
b2,bgr,msb,xy  .. file: data

Обозначение b1,rgb,lsb,xy расшифровывается: бит 1 (младший), каналы RGB, порядок LSB, обход пикселей по X затем Y. Это самая стандартная конфигурация LSB-стеганографии в CTF.

Если zsteg не даёт результата — берём Stegsolve. Это графическое Java-приложение для ручного просмотра битовых плоскостей каждого канала. Иногда в красном канале (Red plane 0) спрятан QR-код или текст, который zsteg не распознал как строку, но глаз видит мгновенно. Stegsolve скачивается с GitHub (репозиторий eugenekolo/sec-tools) и запускается через java -jar stegsolve.jar.

Принципиальное ограничение: zsteg работает только с PNG и BMP. Для JPEG LSB-стеганография применяется крайне редко — сжатие с потерями разрушает младшие биты при каждом сохранении. Если задание даёт JPEG и намекает на LSB — проверьте file, возможно реальный формат другой.

Для нестандартных случаев (данные записаны в один канал, в обратном порядке бит или с произвольным смещением) пригодится ручной скрипт на Python с Pillow:

from PIL import Image
img = Image.open('target.png').convert('RGB')  # convert ensures RGB mode for P/L/RGBA images
px = img.load()
bits = []
for y in range(img.height):
    for x in range(img.width):
        r, g, b = px[x, y]
        bits.extend([r & 1, g & 1, b & 1])
bits = bits[:len(bits) - len(bits) % 8]  # trim to multiple of 8
data = bytes(int(''.join(map(str, bits[i:i+8])), 2)
             for i in range(0, len(bits), 8))
print(data[:200])

Скрипт извлекает LSB только из каналов RGB. Если данные спрятаны в альфа-канале (который zsteg проверяет автоматически), замените convert('RGB') на convert('RGBA') и добавьте обработку четвёртого значения. Это отправная точка — дальше экспериментируйте с комбинациями каналов и порядком обхода пикселей.

Steghide: как пользоваться для извлечения и брутфорса паролей

steghide — старый добрый инструмент для стеганографии, работающий с четырьмя форматами: JPEG, BMP, WAV и AU. В отличие от LSB-методов, steghide использует собственный алгоритм встраивания с шифрованием, и без пароля данные просто так не вытащить.

Базовая команда: steghide extract -sf target.jpg. Если данные встроены без пароля — достаточно нажать Enter при запросе passphrase. По данным hoppersroppers.org, steghide в связке со stegsolve решает до 90% стего-тасков начального уровня — авторы заданий часто не устанавливают пароль или используют пустую строку. Не нажать Enter на запрос passphrase — одна из самых частых ошибок новичков. Серьёзно, я видел это на каждом втором CTF.

Когда пароль установлен, остаётся брутфорс. Два инструмента на выбор:

stegcracker — обёртка над steghide для словарных атак. Команда: stegcracker target.jpg /usr/share/wordlists/rockyou.txt. Минус — скорость: steghide выполняет полную расшифровку при каждой попытке, поэтому перебор rockyou.txt (порядка 14 миллионов записей) растягивается на часы. В write-up на TryHackMe (CTF-BasicSteganography) отдельно предупреждают: «This specific action can take several hours».

stegseek — быстрая альтернатива, работающая на порядки быстрее за счёт прямого разбора формата steghide без полного вызова утилиты на каждую попытку. Тот же rockyou.txt обрабатывается за минуты вместо часов. Запуск аналогичен: stegseek target.jpg rockyou.txt. На Kali ставится через apt, для других дистрибутивов — сборка из исходников на GitHub. Если есть выбор между stegcracker и stegseek — берите stegseek, не пожалеете.

Частая ловушка: задание даёт PNG, а участник пытается запустить steghide. Утилита не поддерживает PNG — только JPEG, BMP, WAV и AU. Для PNG нужны zsteg, stegsolve или openstego. Эта ошибка стоит минут отладки на каждом втором CTF.

Стеганография в аудиофайлах: спектрограммы и скрытые частоты

Аудио-стеганография в CTF — отдельная категория, где визуальные инструменты важнее слуховых. Два основных вектора: изображение, закодированное в спектрограмму, и LSB-данные в WAV-сэмплах.

Спектрограмма — самый «классический» аудио-стего. Автор таска кодирует текст или QR-код в высокочастотный диапазон WAV-файла. На слух — тишина или лёгкий шум. На спектрограмме — читаемое сообщение. Красиво, когда видишь это в первый раз.

Инструменты: Sonic Visualiser (больше контроля над параметрами — рекомендую для CTF) или Audacity (переключить вид трека на «Спектрограмму»). Ключевые настройки для обнаружения: увеличить верхнюю границу частоты до 20-22 кГц (флаги часто прячут в диапазоне 18-20 кГц, неслышном для большинства людей) и выбрать логарифмическую шкалу. Без этих настроек сообщение будет незаметным даже на спектрограмме — я сам первый раз потратил полчаса, пока не догадался крутануть верхнюю границу.

LSB в WAV. WAV — несжатый формат, каждый аудиосэмпл хранится как 16-битное число. Младший бит каждого сэмпла может нести полезные данные. WavSteg (pip install WavSteg) извлекает LSB: python3 -m WavSteg -r -i target.wav -o output.txt -n 1 забирает по одному младшему биту из каждого сэмпла.

MP3 и сжатые форматы. Сжатие с потерями разрушает LSB-данные, поэтому для MP3 используются другие методы: метаданные ID3 (проверяются через exiftool target.mp3), скрытые фреймы или стеганография на уровне параметров кодирования. В CTF MP3-стеганография встречается заметно реже WAV.

Практическая подсказка: если задание даёт аудиофайл подозрительно малой длительности (1-3 секунды) при большом размере — данные, вероятно, спрятаны не в аудио, а приклеены к файлу. Запускайте binwalk и strings прежде, чем открывать аудиоредактор.

Appended data и magic bytes: скрытые данные за границей файла

Этот приём встречается на CTF регулярно, и он же вызывает больше всего ступора у новичков. Браузеры и просмотрщики изображений читают файл до маркера конца формата (для JPEG — 0xFFD9, для PNG — чанк IEND) и игнорируют всё что после. Автор задания дописывает архив, текст или другое изображение после маркера конца — визуально файл выглядит нормально.

Обнаружение: binwalk покажет вторую сигнатуру. Если binwalk видит только «End of Zip archive» без начала — magic bytes повреждены. В writeup на dominicbreuker.com описан характерный случай: ZIP приклеен к JPEG, первый байт PK (hex 50 4B 03 04) заменён на FF 4B 03 04. Утилита stegdetect сигнализирует: appended(227)<[nonrandom][data]>, а stegoVeritas печатает сырые байты trailing data, в которых дважды читается строка flag.txt.

Алгоритм при подозрении на appended data с повреждёнными сигнатурами:

  1. Просмотреть хвост файла: xxd target.jpg | tail -30
  2. Найти маркер конца JPEG (FF D9) и проверить байты после него
  3. Сверить байты с известными сигнатурами — ZIP начинается с 50 4B 03 04, RAR — с 52 61 72 21, gzip — с 1F 8B
  4. Исправить повреждённые байты в hex-редакторе: hexedit target.jpg
  5. Вырезать вложенный файл: dd if=target.jpg of=extracted.zip bs=1 skip=<offset> или автоматически через foremost -i target.jpg

Для PNG есть ещё один хитрый метод сокрытия — занижение высоты в заголовке IHDR. Реальная картинка содержит больше строк пикселей, чем указано в заголовке, и нижняя часть просто не отрисовывается. Обнаружение: pngcheck -v target.png покажет предупреждение о несоответствии между заявленным размером и реальным объёмом IDAT-данных. Исправление: увеличить высоту в байтах 4-7 блока IHDR и пересчитать CRC блока. Звучит страшно, но на практике — пара минут в hex-редакторе.

Частые ошибки новичков в forensics CTF заданиях

Доверие расширению файла. Файл flag.png может оказаться JPEG, ZIP, ELF-бинарником или текстовым файлом. Первая команда — всегда file. Без исключений. Это не рекомендация, это правило.

Один инструмент на все случаи. steghide работает только с JPEG, BMP, WAV и AU. zsteg — только с PNG и BMP. Stegsolve — только визуальный анализ. Ни один инструмент для стеганографии не покрывает все форматы и методы. Чек-лист из начала статьи существует именно чтобы не застревать на одном шаге.

Игнорирование strings. Кажется слишком примитивным, но strings обнаруживает флаг примерно в каждом пятом стего-таске начального уровня. Авторы CTF-заданий прячут флаг в comment-секциях бинарного формата или тупо конкатенируют текст с бинарными данными.

Пропуск пустого пароля в steghide. При запросе passphrase нужно нажать Enter. Часто данные встроены без пароля, а участник решает, что «steghide не работает», и уходит к другому инструменту. Минута проверки экономит часы.

Незнание бинарной структуры форматов. Если вы не понимаете архитектуру PNG (сигнатура 89 50 4E 47 0D 0A 1A 0A → IHDR → tEXt → IDAT → IEND), то не заметите занижение высоты в IHDR или данные после IEND. Базовое знание структуры основных форматов — необходимость для категории Forensics и Stego.

Брутфорс до анализа. Запустить stegcracker с rockyou.txt и уйти ждать — соблазнительно, но неэффективно. Сначала все быстрые шаги. Часто подсказка к паролю лежит в метаданных (Comment или Description в EXIF), в имени файла или в описании задания на CTF-платформе.

Навыки стегоанализа применимы далеко за пределами CTF. Реальные вредоносные программы используют стеганографию для маскировки C2-коммуникаций — техника Steganography (T1001.002, тактика Command and Control по MITRE ATT&CK) и обфускации полезной нагрузки (T1027.003, тактика Stealth). Некоторые семейства малвари, по данным отчётов ИБ-вендоров, прячут команды C2-серверу прямо в картинках, выложенных на легитимных хостингах. Инструменты обнаружения — binwalk, strings, hex-анализ — те же самые, что разобраны в этой статье.

Разбираю стего-таски не первый год и вижу устойчивый паттерн: 80% заданий ломаются первыми четырьмя шагами чек-листа (filestringsexiftoolbinwalk). Оставшиеся 20% делятся примерно поровну между LSB-стеганографией и password-based steghide. Экзотика вроде PNG column padding или Unicode zero-width characters попадается на финалах — но к тому моменту интуиция уже наработана десятками решённых тасков. Категория Stego раздражает многих CTF-игроков именно потому, что нет серебряной пули — одного инструмента на все случаи. Но в этом и ценность: стеганография в CTF учит системному мышлению, а не нажиманию кнопок. Не коллекционируйте утилиты — отрабатывайте чек-лист, пока порядок действий не станет рефлексом. Writeup'ы дают понимание, но навык формируется только на практике с прогрессией по уровням — если хочешь не просто читать разборы, а проходить каждый вектор самому, на codeby.school есть WAPT с лабой на каждый кейс и ментором при затыке.

🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».

Поделиться

0 комментариев

Пожалуйста, войдите, чтобы оставить комментарий.

Загрузка комментариев...

Читайте также

Netcat и socat для CTF: шеллы и проброс портов

13 мин.

5

Netcat и socat для CTF: шеллы и проброс портов

Пошаговый разбор: reverse и bind shell, стабилизация TTY, шифрование через TLS, проброс портов. Каждый флаг, типичные ошибки и порядок fallback.

22 СЕНТЯБРЬ, 2026

Insecure Deserialization в CTF: PHP, Python, Java

12 мин.

4

Insecure Deserialization в CTF: PHP, Python, Java

Пошаговая эксплуатация insecure deserialization в CTF: PHP unserialize, Python pickle RCE, Java ysoserial. Разбор CVE-2020-15148 и реальных gadget chains.

22 СЕНТЯБРЬ, 2026

Linux privilege escalation SUID SGID: гайд для CTF

15 мин.

12

Linux privilege escalation SUID SGID: гайд для CTF

Разбираем SUID, SGID и sticky bit от механики до эксплуатации: 3 CTF-сценария с командами, чек-лист privesc, GTFOBins и типичные ошибки новичков

21 СЕНТЯБРЬ, 2026