Статья

Лента / Публикация

Мой первый CTF

Dekswood 5 мин чтения
Обложка публикации

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

Сразу признаюсь: за отведённое время я бы не справился, так как за компьютер смог сесть только после официального окончания соревнований. К счастью, CTF продлили, и у меня появился шанс довести дело до конца. Возможно, в моём решении был элемент везения или «вайб-кодинга», но так уж сложилось. Главное — я начал нарабатывать скилл и насмотренность, а это бесценно.

Этап 1: Первое знакомство с «битым» изображением

Мы получили файл osint_kraken.png, который не открывался стандартными просмотрщиками. Первое, что приходит в голову — проверить, что это вообще за файл и не повреждён ли он намеренно.

Базовые проверки:

bash
file osint_kraken.png           # Проверка типа файла
exiftool osint_kraken.png       # Проверка метаданных
pngcheck osint_kraken.png       # Проверка структуры PNG

Результат pngcheck был показательным: CRC error in chunk IHDR. Файл оказался намеренно «испорченным» — классический приём в стеганографии.

Hex-анализ:

bash
xxd osint_kraken.png | head -40  # Просмотр заголовка

Сигнатура PNG (89 50 4E 47) была на месте, что означало: файл действительно является PNG-изображением, но с изменёнными данными внутри.

Этап 2: Понимание метода сокрытия

Из статьи-подсказки я узнал, что изменяя размеры в блоке IHDR и не обновляя контрольную сумму (CRC), можно скрыть часть изображения, не удаляя её окончательно. Структура критически важного блока IHDR:

  • Смещение 16-23 байт: ширина и высота изображения (по 4 байта).

  • Смещение 29-32 байт: CRC блока IHDR.

Этап 3: Восстановление изображения

Первым делом нужно было исправить CRC, чтобы файл стал валидным PNG. Для этого:

bash
cp osint_kraken.png fixed.png
# pngcheck покажет что-то вроде: "computed XXXXXXXX, expected YYYYYYYY"
# Меняем CRC на вычисленное значение (XXXXXXX):
printf '\xXX\xXX\xXX\xXX' | dd of=fixed.png bs=1 seek=29 conv=notrunc

Файл fixed.png наконец-то открылся, но изображение оказалось обрезанным — в нижней части был виден лишь фрагмент QR-кода.

Этап 4: Восстановление полного QR-кода

Гипотеза была очевидной: QR-код скрыт «за границами» видимой области, то есть исходная высота изображения была больше. Нужно было подобрать правильное значение высоты.

Я загуглил простой bash-скрипт для автоматического перебора:

  • Перебирал дельты от 1 с шагом 10 и до 1000 пикселей.

  • Для каждой дельты менял высоту в блоке IHDR и пересчитывал CRC.

  • Сохранял каждый валидный PNG в отдельный файл.

 

bash
#!/bin/bash
for delta in $(seq 1 10 1000); do
    echo "Пробуем delta = $delta"
    cp original.png test_delta_${delta}.png
    
    # Вычисляем новую высоту
    new_height=$((2912 + delta))
    
    # Конвертируем в hex (big-endian)
    h1=$(( (new_height >> 24) & 0xFF ))
    h2=$(( (new_height >> 16) & 0xFF ))
    h3=$(( (new_height >> 8) & 0xFF ))
    h4=$(( new_height & 0xFF ))
    
    # Заменяем высоту
    printf "\\x$(printf '%02x' $h1)\\x$(printf '%02x' $h2)\\x$(printf '%02x' $h3)\\x$(printf '%02x' $h4)" | \
        dd of=test_delta_${delta}.png bs=1 seek=20 conv=notrunc 2>/dev/null
    
    # Получаем новый CRC
    crc_output=$(pngcheck test_delta_${delta}.png 2>&1 | grep "computed")
    if echo "$crc_output" | grep -q "computed"; then
        computed_crc=$(echo "$crc_output" | sed 's/.*computed \([0-9a-f]*\),.*/\1/')
        
        # Заменяем CRC
        c1=$(echo $computed_crc | cut -c1-2)
        c2=$(echo $computed_crc | cut -c3-4)
        c3=$(echo $computed_crc | cut -c5-6)
        c4=$(echo $computed_crc | cut -c7-8)
        
        printf "\\x$c1\\x$c2\\x$c3\\x$c4" | \
            dd of=test_delta_${delta}.png bs=1 seek=29 conv=notrunc 2>/dev/null
        
        # Проверяем валидность
        if pngcheck test_delta_${delta}.png >/dev/null 2>&1; then
            echo "  ✓ Валидный PNG с высотой $new_height"
            # Пробуем сканировать QR-код
            zbarimg test_delta_${delta}.png 2>/dev/null && echo "  ✓ QR-код найден!" && exit 0
        fi
    fi
done

Сохраните как find_qr.sh, запустите:

bash
chmod +x find_qr.sh
./find_qr.sh

 

Затем вручную открыл полученные изображения и нашёл тот, где QR-код отображался полностью.

 

Этап 5: Сканирование QR-кода и небольшая неудача

QR-код я отсканировал с помощью приложения на телефоне. Он вёл на ссылку Яндекс.Диска, где лежало второе изображение — 20231111_155824.jpg.

Тут я совершил ошибку: вместо того чтобы сразу проанализировать новую картинку, я решил поискать её в интернете. Нашёл мемориальную табличку и почему-то подумал, что флаг — это имя «А.А. Мачура». Естественно, это оказалось неверным. Мне пришлось просить подсказку, после которой я вернулся на правильный путь и повторил для второго изображения Этап 1.

Этап 6: Анализ второй картинки

Проверка метаданных дала результат:

bash
exiftool 20231111_155824.jpg

В EX-данных обнаружились GPS-координаты:

  • Широта: 45°1'7.38" N

  • Долгота: 38°58'7.51" E

Этап 7: Интерпретация GPS-координат

Я преобразовал координаты в десятичный формат (спасибо ИИ за помощь):

  • 45°1'7.38" N = 45.0187167

  • 38°58'7.51" E = 38.9687528

Поиск по координатам в Google Maps (оказалось, что в Яндекс.Картах они отображаются немного иначе) привёл к конкретному дому в Краснодаре. Переключившись на Яндекс.Карты для удобства, я нашёл то, что искал.

Флагом оказалось имя человека, связанное с этим адресом.

Заключение

wqvQotGLINC00YPQvNCw0LXRiNGMLCDRjdGC0L4g0LrQvtC90LXRhj/CuyDigJQgwqvQndC10YIuINCt0YLQviDRgtC+0LvRjNC60L4g0L3QsNGH0LDQu9C+wrsu

Мой первый CTF по стеганографии научил меня нескольким важным вещам:

  1. Не игнорируйте основы. Команды fileexiftool и pngcheck должны стать рефлексом.

  2. Доводите анализ до конца. Если нашли новое изображение — применяйте к нему все те же методы.

  3. Контекст имеет значение. GPS-координаты — это не просто числа, а указание на место, которое может хранить ответ.

  4. Не сдавайтесь после первой ошибки. Ошибочная догадка — часть процесса, главное — вовремя вернуться на правильный путь.

Этот опыт стал отличным стартом в мире CTF. Спасибо команде KRAKEN-ACADEMY