
На одном из недавних CTF-ивентов задача за 300 очков висела нерешённой полтора часа: обычный JPEG с котиком, 200 КБ, без видимых аномалий. strings — пусто, exiftool — чисто, binwalk — тишина. Флаг оказался внедрён через steghide с паролем из четырёх символов, который stegseek подобрал за 8 секунд по rockyou.txt. Вся разница между «решили» и «не решили» — знание правильного порядка инструментов и понимание, когда один заканчивает работу и начинает другой.
Я три года собирал этот порядок по кускам — из собственных провалов на соревнованиях, из чужих разборов, из задач, где потратил часы на угадывание вместо системного перебора. Ниже — от первого взгляда на файл до извлечения флага, с разбором ловушек, на которых спотыкается большинство.
steghide, binwalk, exiftool, foremost — ставятся через aptgem install zsteg)java -jar stegsolve.jar)stegseek (deb-пакет с GitHub), Audacity, Sonic Visualizer, Python 3.8+ с PillowПрежде чем запускать специализированные инструменты для стеганографии CTF, нужно собрать базовую информацию. Этап занимает меньше минуты, но способен закрыть задачу целиком — если автор задания не заморачивался.
Шаг 1 — определить реальный тип файла. Расширение в CTF часто врёт. Файл flag.jpg может оказаться PNG, ZIP-архивом или ELF-бинарником. Команда file flag.jpg покажет реальный формат по magic bytes — сигнатурным байтам в начале файла. PNG начинается с 89 50 4E 47, JPEG — с FF D8 FF, ZIP — с 50 4B 03 04. Если file сообщает, что предполагаемый JPEG на самом деле «PNG image data» — переименуйте файл и работайте с правильным форматом. Шаг тривиальный, но на соревнованиях его пропускают регулярно.
Шаг 2 — поиск текстовых строк. strings flag.png | grep -i flag — первое, что стоит запустить. По данным ресурсов по CTF-форензике (hacklido.com, 0xrick.github.io), заметная часть задач начального уровня прячет флаг в виде читаемого текста внутри бинарного файла. Пусто? Попробуйте strings -n 6 flag.png для фильтрации строк от шести символов. Иногда флаг закодирован в Base64, и тогда strings flag.png | grep -iE '[A-Za-z0-9+/=]{20,}' поможет выловить подозрительные последовательности.
Шаг 3 — анализ метаданных изображений. exiftool flag.png выводит EXIF, IPTC и XMP-метаданные. В CTF-задачах авторы прячут подсказки или флаг в полях Comment, Artist, Copyright, Description. Обратите внимание на GPS-координаты — они могут указывать на следующий этап задания. Нестандартное значение в любом мета-поле — почти наверняка зацепка.
Шаг 4 — hex-анализ. Откройте файл в hex-редакторе (xxd flag.png | tail -30 или GUI — HxD, Bless, GHex) и проверьте область после маркера конца файла: для PNG это IEND, для JPEG — FF D9. Данные, дописанные после EOF-маркера, — классическая техника скрытия данных в файлах. Если после FF D9 в JPEG идут байты 50 4B (сигнатура ZIP) — внутри спрятан архив.
На этом этапе цифровая стеганография в CTF отделяется от базового анализа. Если ничего не обнаружено — переходим к специализированным инструментам.
Типичная ошибка — запускать всё подряд, не понимая, какой инструмент для какого формата заточен. Ниже — trade-off таблица с реальными ограничениями.
| Инструмент | Форматы | Преимущества | Ограничения | Когда использовать | Когда не использовать |
|---|---|---|---|---|---|
| steghide | JPEG, BMP, WAV, AU | Шифрование с паролем, низкий порог входа | Не поддерживает PNG; требует пароль | JPEG/BMP с подозрением на внедрённые данные | Любые PNG-файлы |
| zsteg | PNG, BMP | Перебирает все LSB-комбинации каналов, быстрый | Только PNG/BMP, нет аудио | PNG, подозрение на LSB-кодирование | JPEG (сжатие уничтожает LSB) |
| binwalk | Любые | Находит вложенные файлы по сигнатурам, автоизвлечение | Не детектирует LSB-стеганографию | Файл подозрительно большой или данные после EOF | Задачи на LSB без вложений |
| Stegsolve | Изображения (все) | Визуальный анализ битовых плоскостей, GUI | Требует Java, нет автоматического извлечения | QR-коды и паттерны в цветовых каналах | Аудиофайлы |
| foremost | Любые | Карвинг файлов по headers/footers | Не определяет стеганографию | Восстановление из дампов и образов | Задачи на LSB и спектрограммы |
| stegseek | JPEG, BMP, WAV, AU | Brute-force steghide-паролей, в 1000+ раз быстрее stegcracker | Только steghide-файлы | Неизвестный пароль к steghide | Файлы, обработанные другими инструментами |
| Sonic Visualizer | WAV, MP3, FLAC, Ogg | Спектрограммы, визуализация частот | GUI, не автоматизируется | Аудиозадачи со скрытыми визуальными сообщениями | Изображения |
Ключевое различие, которое новички упускают: zsteg и steghide решают разные задачи. zsteg анализирует LSB-слои в PNG — пассивный анализ существующих данных. steghide — активный инструмент, который шифрует и внедряет с использованием пароля. Путать их — терять время. Я видел, как команда 40 минут гоняла steghide по PNG-файлу, хотя steghide PNG в принципе не поддерживает.
Отдельно упомяну stegoveritas (pip3 install stegoveritas + stegoveritas_install_deps) — мультиформатный комбайн, который прогоняет кучу тестов автоматически. Из-за этого работает медленнее специализированных утилит. Полезен как «последний шанс», когда целевые инструменты ничего не нашли.
zsteg — основной инструмент для работы с Least Significant Bit стеганографией в PNG. LSB-кодирование меняет последний (наименее значимый) бит каждого байта цветового канала. Для глаза разница между значением пикселя 254 и 255 неотличима, но в этих битах может храниться полноценное сообщение.
Работает если: файл — PNG или BMP без сжатия с потерями. Данные внедрены через LSB-подмену в цветовых каналах (R, G, B) или альфа-канале.
Не работает если: файл — JPEG (сжатие с потерями перезаписывает младшие биты), данные внедрены через steghide (другой алгоритм), данные скрыты в метаданных или после EOF-маркера.
Установка: gem install zsteg. Базовый запуск zsteg flag.png проверяет несколько стандартных конфигураций LSB. Для полного анализа — zsteg -a flag.png: перебираются все комбинации каналов (RGB, BGR, RBG и т.д.), порядок битов (MSB/LSB), направления чтения (по строкам и столбцам). Типичный вывод при обнаружении:
b1,rgb,lsb,xy .. text: "flag{lsb_1s_n0t_s0_h1dd3n}"
b1,bgr,lsb,xy .. file: PNG image data, 32 x 32
b2,r,lsb,xy .. text: "nothing here"
Строка b1,rgb,lsb,xy расшифровывается так: первый бит (b1), каналы в порядке RGB, least significant bit, чтение по строкам (x) затем по столбцам (y). Если zsteg обнаружил текст или заголовок файла — данные перед вами. Для извлечения конкретного payload: zsteg -E b1,rgb,lsb,xy flag.png > extracted.bin.
Когда zsteg -a выдаёт десятки строк нечитаемого мусора — не паникуйте. Инструмент проверяет сотни комбинаций, большинство не содержат осмысленных данных. Ищите строки с ASCII-текстом, заголовками известных форматов (PNG, PK, %PDF) или подозрительно длинные последовательности.
Частая ловушка: автор задачи использует нестандартный порядок каналов. Если данные внедрены в порядке BGR с MSB вместо LSB — базовый zsteg flag.png без -a их пропустит. Флаг -a — обязателен на соревнованиях. Без него вы просто не увидите половину возможных вариантов.
steghide работает с JPEG, BMP, WAV и AU — форматами, которые zsteg не поддерживает (или поддерживает частично). Принципиальное отличие: steghide внедряет данные и защищает их парольной фразой. Без правильного пароля извлечь содержимое не получится.
Работает если: файл — JPEG, BMP, WAV или AU. Данные внедрены через steghide (у инструмента собственный формат внедрения, несовместимый с другими).
Не работает если: файл — PNG. Это одно из самых частых заблуждений новичков — steghide PNG не поддерживает, точка. Также steghide не извлечёт данные, внедрённые через outguess или openstego — у каждого свой формат.
Чтобы спрятать данные в картинке: steghide embed -cf cover.jpg -ef secret.txt — инструмент запросит пароль. Извлечение: steghide extract -sf cover.jpg — снова нужен пароль. Проверка без извлечения: steghide info cover.jpg.
В CTF-задачах пароль бывает пустым. Попробуйте steghide extract -sf cover.jpg -p "" — это первое, что стоит проверить. Не сработало — ищите пароль в метаданных (поле Comment из exiftool), в имени файла, в описании задачи на платформе. Авторы любят прятать подсказки на виду.
Если пароль неизвестен и подсказок нет — brute-force. Два варианта:
stegcracker (pip3 install stegcracker) вызывает steghide для каждого пароля как отдельный процесс. На rockyou.txt с 14 миллионами записей перебор занимает часы. Команда: stegcracker cover.jpg /usr/share/wordlists/rockyou.txt. Честно говоря, на CTF-ивенте с ограниченным временем это почти бесполезно.
stegseek — замена на C++, которая делает то же самое, но в тысячи раз быстрее: полный перебор rockyou.txt завершается за секунды. Установка: скачать deb-пакет с GitHub-репозитория, затем dpkg -i stegseek_*.deb. Запуск: stegseek cover.jpg /usr/share/wordlists/rockyou.txt. При нахождении пароля данные извлекаются автоматически.
Если у вас Debian или Ubuntu — используйте stegseek, без вариантов. Синтаксис идентичен stegcracker, скорость на порядки выше. stegcracker оправдан только когда установить stegseek невозможно (экзотическая ОС, нет прав на dpkg).
binwalk решает другой класс задач: поиск файлов, вложенных внутрь других файлов. Это не стеганография в строгом смысле — скорее скрытие данных в файлах через конкатенацию или внедрение в неиспользуемые области. Но на CTF такие задачи маскируются под stego, и binwalk — первое, что их вскрывает.
Работает если: внутри файла есть вложение с распознаваемой сигнатурой (ZIP, RAR, PNG, PDF, gzip, ELF и т.д.), или данные дописаны после EOF-маркера основного файла.
Не работает если: данные закодированы через LSB, зашифрованы или лишены стандартной файловой сигнатуры.
Базовый анализ: binwalk flag.png — выводит все обнаруженные сигнатуры. Пример вывода:
DECIMAL HEXADECIMAL DESCRIPTION
-------------------------------------------
0 0x0 PNG image, 800 x 600
98304 0x18000 Zip archive data, name: secret.txt
98450 0x18092 End of Zip archive
Автоматическое извлечение: binwalk -e flag.png — результат окажется в директории _flag.png.extracted/. Для рекурсивного извлечения: binwalk --dd='.*' flag.png.
Нюанс, который стоит держать в голове: binwalk ищет сигнатуры по фиксированным смещениям. Если автор задачи намеренно повредил magic bytes вложенного файла (например, заменил первые два байта ZIP), binwalk его не обнаружит. Тут спасает только ручной hex-анализ.
Альтернатива для карвинга — foremost. Команда foremost -i flag.png -o output_dir/ восстанавливает файлы по заголовкам и футерам. foremost иногда находит то, что binwalk пропускает, поэтому на соревнованиях стоит запускать оба — 10 секунд лишних, зато шанс не упустить вложение.
Аудиозадачи на CTF-соревнованиях встречаются реже изображений, но когда появляются — многие команды теряют время, потому что не знают, с какого конца подступиться. Между тем техники скрытия подчиняются аналогичной логике.
Самый распространённый приём — скрытие визуального сообщения в спектрограмме. Откройте WAV-файл в Sonic Visualizer, добавьте слой спектрограммы (Layer → Add Spectrogram) — и увидите текст или QR-код, нарисованный частотами. Audacity тоже умеет показывать спектрограммы (смена вида трека на Spectrogram), но Sonic Visualizer даёт более тонкую настройку визуализации.
Обращайте внимание на высокочастотный диапазон — выше 15 кГц. Ухо эти частоты почти не различает, что делает их удобным местом для скрытия информации. В Sonic Visualizer увеличьте масштаб по вертикальной оси и поэкспериментируйте с цветовой схемой — иногда сообщение видно только при определённой палитре. Я однажды минут двадцать крутил настройки, пока не переключил на «sunset» — и QR-код буйком всплыл.
Тональные сигналы (писки, длинные и короткие гудки) в аудиофайле — возможно, азбука Морзе или DTMF (тоновый набор телефонного номера). Для морзе используйте онлайн-декодеры или расшифруйте визуально по спектрограмме. DTMF-тоны декодируются через multimon-ng: multimon-ng -t wav -a DTMF file.wav.
WAV-файлы хранят несжатые семплы — к ним применима та же LSB-техника, что и к изображениям. steghide работает с WAV и AU напрямую. Для ручного LSB-анализа аудио есть WavSteg (Python-скрипт с GitHub): python3 WavSteg.py -r -s audio.wav -o output.txt -b 1 — извлекает данные из младшего бита каждого семпла.
Типичная ошибка: при получении аудиозадачи сразу бросаться на спектрограмму, проигнорировав базовые проверки. Начинайте с file, strings, exiftool, binwalk — ровно так же, как с изображениями. Встречаются задачи, где флаг лежит в EXIF-комментарии WAV-файла. Просто exiftool audio.wav — и готово, а вы бы полчаса ковыряли спектрограмму.
Stegsolve — Java-приложение для переключения визуализации между битовыми плоскостями и цветовыми каналами. Запуск: java -jar stegsolve.jar, затем File → Open.
Стрелками переключайтесь между режимами: Red plane 0, Red plane 1, ..., Green plane 0, ..., Alpha plane 0 и т.д. Plane 0 — младший бит канала. Если в младшем бите красного канала скрыт QR-код, вы увидите его на слое «Red plane 0» как чёрно-белый паттерн. Иногда щёлкаешь по плоскостям и на третьем клике — бац, QR-код на весь экран.
Stegsolve также умеет комбинировать два изображения (Image Combiner) — полезно, когда задача содержит два похожих файла, а различия между ними несут скрытое сообщение. Frame Browser помогает с анимированными GIF: иногда один кадр из сотни содержит флаг.
Для ручного извлечения LSB без инструментов подходит Python с Pillow:
from PIL import Image
img = Image.open('secret.png')
bits = []
for y in range(img.height):
for x in range(img.width):
r, g, b = img.getpixel((x, y))[:3]
bits.extend([r & 1, g & 1, b & 1])
data = bytes(int(''.join(map(str, bits[i:i+8])), 2)
for i in range(0, len(bits), 8))
print(data[:200])
Скрипт извлекает младший бит из каждого канала RGB попиксельно и собирает биты в байты. Если данные внедрены в LSB — первые байты вывода покажут осмысленный текст или заголовок файла. Это пример для понимания концепции; для боевой работы используйте zsteg или stegoveritas.
Порядок действий при получении файла на stego-задачу:
file challenge_file — определяем реальный тип. Расширению не доверяем.strings challenge_file | grep -i flag — ищем флаг в открытом виде. Варианты: grep -i ctf, grep -i key, grep -iE '[A-Za-z0-9+/=]{20,}' для Base64.exiftool challenge_file — все метаданные. Особое внимание на Comment, Artist, Description.xxd challenge_file | tail -20 — конец файла. Есть ли данные после EOF-маркера?binwalk challenge_file — вложенные файлы. Нашли — binwalk -e challenge_file.zsteg -a challenge_file
- JPEG/BMP/WAV/AU — steghide extract -sf challenge_file -p "" (пустой пароль), затем stegseek challenge_file rockyou.txt
- Любое изображение — Stegsolve: визуальный анализ битовых плоскостей
- WAV/MP3 — Sonic Visualizer: спектрограмма, особенно диапазон выше 15 кГцforemost -i challenge_file, stegoveritas challenge_file, ручной hex-анализ для поиска повреждённых заголовков или нестандартных смещений.flag.png.zip — сначала распакуйте архив, потом анализируйте изображение.image.jpg с PNG-заголовком — file покажет несоответствие, но если шаг 1 пропущен — потратите время на steghide вместо zsteg.Подготовьте тестовые файлы для каждого инструмента — это занимает 10 минут, после чего весь алгоритм воспроизводится без доступа к интернету.
Стенд:
flag.txt с содержимым flag{test_steghide_123}.steghide embed -cf photo.jpg -ef flag.txt -p "test". Попробуйте извлечь: steghide extract -sf photo.jpg -p "test", а затем brute-force: stegseek photo.jpg rockyou.txt.zsteg -a modified.png — убедитесь, что данные обнаруживаются.cat photo.png secret.zip > combined.png. Проверьте binwalk combined.png и binwalk -e combined.png.Навыки форензики файлов CTF переносятся в реальный мир напрямую. В MITRE ATT&CK стеганография фигурирует как техника обфускации вредоносных файлов (T1027.003, Defense Evasion) и как канал управления C2-инфраструктурой (T1001.002, Command and Control). APT-группы скрывают полезные нагрузки в изображениях на легитимных хостингах — и аналитику SOC пригодятся те же binwalk, zsteg и steghide для анализа подозрительных файлов. Те, кто формулу LSB на бумаге усвоил, могут прощупать её руками на HackerLab.pro — там есть таски в категориях Forensics и Stego, для входа нужна регистрация, после неё открываются задачи всех уровней.
Три года назад я был уверен, что стеганография — «лёгкая» категория в CTF, разминка перед pwn и crypto. Потом четыре часа провозился с задачей, где данные спрятали в младших битах альфа-канала PNG, считываемых по столбцам, с порядком BGRA вместо RGBA. Стандартный zsteg нашёл их только с флагом -a, до которого я добрался последним. С тех пор каждую stego-задачу начинаю одинаково: file, strings, exiftool, binwalk -e, zsteg -a, steghide extract -p "", stegseek — строго в этом порядке, без пропусков. Каждый пропущенный шаг — потенциальные полчаса впустую на угадывание того, что утилита нашла бы за секунду.
Большинство команд проигрывают не потому, что не знают инструменты, а потому что не имеют системы. Stego проверяет не гениальность, а дисциплину. Проверил ли ты конец файла в hex-редакторе? Попробовал ли пустой пароль перед запуском brute-force на полчаса? Возьмите алгоритм из раздела выше, прогоните его на минилабе — и на следующем CTF вы будете тем, кто снимает stego-задачу за 300 очков, пока остальные гадают, какой инструмент запустить.
🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».
0 комментариев
Пожалуйста, войдите, чтобы оставить комментарий.
Загрузка комментариев...