Главная / Блог / Классические шифры CTF: как ломать Виженер, ROT и XOR на реальных задачах

14 мин.00

Классические шифры CTF: как ломать Виженер, ROT и XOR на реальных задачах

Классические шифры CTF: как ломать Виженер, ROT и XOR на реальных задачах

Классические шифры CTF: как ломать Виженер, ROT и XOR на реальных задачах

Три часа на crypto-задачу, которая решалась за пять минут — стандартная история для новичка в CTF. Один из участников нашей команды на последнем соревновании перепробовал AES-дешифровку, RSA-факторизацию и даже стеганографию. А под слоем base64 лежал обычный шифр Виженера с ключом из четырёх букв. Четыре буквы. Три часа.

Классические шифры CTF — Цезарь, Виженер, XOR — составляют основу категории Crypto на большинстве соревнований начального и среднего уровня. Разберём по шагам, как распознавать каждый тип, какие инструменты применять и — самое ценное — как не потратить часы на ложную гипотезу. С кодом на Python, с показом тупиков и с объяснением, почему тупики важнее финального решения.

Требования к окружению (для воспроизведения всех примеров):

  • Python 3.8+ (стандартная библиотека: модули collections, string)
  • Браузер для онлайн-инструментов: CyberChef, dcode.fr, quipqiup.com
  • Опционально: pip install xortool для автоматизации XOR-анализа
  • Специальных требований к RAM, CPU или GPU нет — все примеры работают на любой машине

Как определить тип шифра в crypto-задаче CTF

Первое, что нужно сделать при получении шифротекста в криптографической задаче — не бросаться расшифровывать, а понять, с чем вы имеете дело. Именно тут теряется больше всего времени. Вы полчаса пытаетесь «сломать AES», а перед вами — hex-кодированный текст, который достаточно декодировать одной командой.

Кодировка или шифр: принципиальная разница

Кодировка — способ представления данных, у неё нет секретного ключа. Base64, hex, URL-encoding обратимы без каких-либо секретов: достаточно знать алгоритм. В CTF кодировки постоянно используются как обёртки поверх настоящего шифра — снимаете слой base64, а под ним шифротекст. Матрёшка.

По данным HackTricks Crypto CTF Workflow, типичная crypto-задача CTF — многослойная трансформация: base-кодировка + классическая подстановка + иногда сжатие. Цель — распознать слои и снять их один за другим.

Визуальные признаки основных кодировок:

  • Base64: символы A-Za-z0-9+/, часто заканчивается на = или ==
  • Base32: A-Z2-7, в конце бывает несколько знаков =
  • Hex: только символы 0-9A-Fa-f, всегда чётное количество знаков
  • URL-encoding: последовательности вида %20, %3D

Если после снятия всех слоёв кодирования текст по-прежнему нечитаемый — перед вами шифр.

Визуальные маркеры классических шифров

Шифр Цезаря / ROT: текст выглядит почти как обычные слова. Пробелы, знаки препинания на месте, но буквы «не те». Пример: Uryyb, Jbeyq! — ROT13 от Hello, World!. Видите что-то подобное — начните с ROT.

Шифр Виженера: набор исключительно буквенных символов (латиница), без цифр и спецсимволов. Пробелы чаще всего удалены. Текст обычно длинный — для коротких строк криптоанализ Виженера затруднён, и авторы задач это учитывают.

XOR-шифрование: данные часто представлены в hex или base64. После декодирования из hex часть байтов — непечатаемые символы. В отличие от AES-шифротекста, XOR не имеет блочной структуры: размер не кратен 16 байтам, нет характерного padding в конце.

Моноалфавитная подстановка (не Цезарь): буквенный текст, но без сохранения позиционной структуры алфавита. Каждая буква заменена произвольной другой. Частотный анализ даёт неравномерное распределение, похожее на естественный язык.

Практический чеклист при получении шифротекста (адаптирован из Crypto CTF Workflow, hacktricks.wiki):

  1. CyberChef — операция «Magic». Автоматически пробует частые кодировки и преобразования
  2. Если текст содержит только буквы латиницы — вероятен классический шифр
  3. Если данные бинарные (hex/base64) и после декодирования нечитаемы — попробуйте XOR с однобайтовым ключом
  4. Для длинного буквенного текста проверьте распределение частот символов. Сильно неравномерное — моноалфавитная подстановка. Относительно ровное — полиалфавитная подстановка (Виженер)

ROT13 расшифровка и шифр Цезаря в CTF

ROT13 — частный случай шифра Цезаря со сдвигом 13. В латинском алфавите 26 букв, поэтому ROT13 — собственная обратная функция: применили дважды — получили исходный текст. В CTF это разминочная задача, но именно на ней стоит отработать системный подход, который потом спасёт на более сложных шифрах.

Три способа расшифровки ROT

CyberChef — самый быстрый путь. Загружаете шифротекст, добавляете операцию «ROT13 Brute Force». Инструмент покажет все 25 вариантов сдвига одновременно. Глазами ищете осмысленный текст — обычно он один.

Python в командной строке: python3 -c "import codecs; print(codecs.decode('Uryyb', 'rot_13'))" — для ROT13 работает стандартный модуль codecs. Для произвольного сдвига придётся возиться с арифметикой по модулю 26, но для решения crypto CTF задач быстрее CyberChef.

dcode.fr — сервис автоматически определяет величину сдвига через частотный анализ шифра и показывает наиболее вероятный вариант. Полезен, когда сдвиг неизвестен и текст достаточно длинный.

Подводные камни ROT в CTF

Первая ошибка новичка — пробовать только ROT13 и сдаваться. Сдвиг может быть любым числом от 1 до 25. Проверяйте все 25 вариантов: для человека это визуальная задача на 30 секунд.

Менее очевидный подвох — ROT5 для цифр (сдвиг в диапазоне 0-9) и ROT47 для расширенного ASCII (символы с кодами 33-126). Если стандартный ROT13 по буквам не дал результата, а в тексте есть цифры и спецсимволы — попробуйте ROT47 в CyberChef.

Ещё ловушка: комбинированное кодирование. Текст сначала обработан ROT, затем переведён в base64. Или наоборот. Алгоритм — снимайте слои в обратном порядке, каждый раз проверяя промежуточный результат на осмысленность. Я как-то потратил двадцать минут, пытаясь расшифровать ROT-текст, не заметив, что он был предварительно обёрнут в base32. Снял base32 — и стандартный ROT13 сработал моментально.

XOR-брутфорс CTF: от одного байта до полного ключа

XOR — самый частый «шифр» в CTF после Цезаря. Его популярность в задачах объясняется тем же, чем и популярность у авторов вредоносного ПО: операция проста, обратима и не требует внешних библиотек. В терминологии MITRE ATT&CK обфускация через XOR — техника Obfuscated Files or Information (T1027), а деобфускация — Deobfuscate/Decode Files or Information (T1140). Навык XOR-анализа в CTF напрямую переносится на разбор реальных семплов малвари — это не абстрактное упражнение.

Ключевое свойство XOR для криптоанализа: A ^ B ^ B = A. Операция обратима тем же ключом — шифрование и дешифрование это одна и та же процедура. Свойство подробно описано в материалах ctf101.org в разделе про XOR cipher decryption.

Однобайтовый XOR — перебор 256 вариантов

Если весь текст зашифрован одним байтом, пространство ключей — 256 вариантов. Перебирается мгновенно. Фактически это частный случай техники Brute Force (T1110) с минимальным пространством ключей.

ciphertext = bytes.fromhex("0d06071e0a01001c074504")
for key in range(256):
    result = bytes([b ^ key for b in ciphertext])
    if all(32 <= c <= 126 for c in result):
        print(f"Key 0x{key:02x}: {result.decode()}")

Скрипт (адаптирован из примера ctf101.org) пробует каждый из 256 байтов-ключей и выводит только те варианты, где все символы результата попадают в диапазон печатаемого ASCII. На практике из 256 вариантов печатаемых окажется 5-15 строк, и осмысленная — одна.

Подвох, на который натыкается каждый второй: если оригинальный текст содержал символ переноса строки (\n, код 10) или табуляции (\t, код 9), фильтр по диапазону 32-126 отбросит правильный ответ. Расширяйте нижнюю границу: if all(9 <= c <= 126 for c in result). Мелочь, но стоила мне лишних двадцати минут на CryptoHack.

Ещё ситуация: шифротекст подан не в hex, а в base64 или в виде списка десятичных чисел. Не забудьте декодировать в байты перед XOR-операцией — иначе вы XOR-ите ASCII-коды символов hex-строки, а не фактические байты шифротекста. Звучит очевидно, но на соревновании в три часа ночи это не так очевидно.

Полезный приём — атака известным открытым текстом. Если вы знаете формат флага (например, CTF{ или picoCTF{), XOR-ьте первые байты шифротекста с этими известными байтами. Результат — байты ключа. Для однобайтового XOR достаточно одного совпадения, для многобайтового вы сразу получите фрагмент ключа.

Многобайтовый XOR: определяем длину ключа

Когда ключ длиннее одного байта, он циклически повторяется: N-й байт текста XOR-ится с (N mod len(key))-м байтом ключа. Структурно это XOR-аналог шифра Виженера, и методы атаки — те же: определить длину ключа, разбить на группы, атаковать каждую группу как однобайтовый XOR.

Утилита xortool (pip install xortool) автоматизирует обе стадии. Как описано в материалах ugractf.ru, вызов xortool encrypted.bin покажет вероятные длины ключа. Обычно все кандидаты кратны истинной длине — начинайте с наименьшего. Затем подбираете ключ: xortool -l 7 -c 20 encrypted.bin, где -l — длина ключа, а -c 20 — код самого частого байта в открытом тексте (0x20 = пробел для текста на английском). Результаты расшифровки сохраняются в директорию xortool_out — среди файлов ищете осмысленный.

Ручной метод определения длины — метод Касиски: ищете повторяющиеся последовательности байт в шифротексте. Расстояния между повторами кратны длине ключа. НОД всех расстояний — вероятная длина. Метод надёжен на длинных текстах (сотни байт), на коротких даёт ложные результаты.

И вот что важно понимать: XOR и Виженер — структурно одна и та же операция. Виженер работает с буквами (сложение по модулю 26), XOR — с байтами (сложение по модулю 2). Методы криптоанализа практически идентичны: индекс совпадений, частотный анализ, метод Касиски. Разобрались с одним — освоите оба.

Взлом шифра Виженера через индекс совпадений

Шифр Виженера — полиалфавитная подстановка: каждая буква открытого текста сдвигается на величину, определяемую соответствующей буквой ключевого слова. Ключ повторяется циклически. Этот шифр столетиями считался невзламываемым, пока Фридрих Касиски и Уильям Фридман не разработали методы атаки.

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

Почему частотный анализ шифра напрямую не работает

В шифре Цезаря все буквы сдвинуты на одинаковое число позиций. Самая частая буква шифротекста соответствует самой частой букве языка (для английского — E). Одно наблюдение — один ключ.

В Виженере буква E на позиции 1 может стать H (ключевая буква D), а на позиции 2 — L (ключевая буква H). Частоты символов «размазываются» по нескольким сдвигам. Частотное распределение шифротекста выглядит близким к равномерному — и это, кстати, само по себе диагностический признак полиалфавитной подстановки. Видите «плоское» распределение — перед вами, скорее всего, Виженер или аналогичный полиалфавитный шифр.

Но если мы знаем длину ключа, задача распадается на несколько независимых шифров Цезаря. Позиции 0, keylen, 2 * keylen, ... зашифрованы первой буквой ключа. Позиции 1, keylen + 1, 2 * keylen + 1, ... — второй. Каждую группу можно атаковать частотным анализом отдельно. По сути, вся хитрость — в правильном определении длины ключа.

Индекс совпадений Виженер: находим длину ключа

Индекс совпадений (IC) — вероятность того, что две случайно выбранные буквы текста совпадут. Для обычного английского текста IC составляет приблизительно 0.065-0.068. Для случайного набора из 26 равновероятных букв IC — приблизительно 0.038 (1/26).

Идея: разбиваете шифротекст на группы по предполагаемой длине ключа. Считаете средний IC по всем группам. При правильной длине IC будет близок к 0.065, при неправильной — к 0.038. Правильная длина выделяется резким скачком IC на фоне остальных.

from collections import Counter

def ic(text):
    text = [c for c in text.upper() if c.isalpha()]
    n = len(text)
    if n < 2:
        return 0.0
    freq = Counter(text)
    return sum(f * (f - 1) for f in freq.values()) / (n * (n - 1))

def guess_key_length(ct, max_len=20):
    ct = [c for c in ct.upper() if c.isalpha()]
    for kl in range(1, max_len + 1):
        groups = [ct[i::kl] for i in range(kl)]
        avg = sum(ic(g) for g in groups) / kl
        print(f"Len {kl:2d}: IC = {avg:.4f}")

Вызов guess_key_length("ВАШШИФРОТЕКСТ") выведет IC для каждой предполагаемой длины от 1 до 20. Ищите резкий рост до значений 0.06+.

Типичная ошибка: взять первую длину с высоким IC и не проверить остальные. Если истинная длина ключа 4, то длины 8, 12, 16 тоже покажут повышенный IC — потому что часть групп содержит позиции с одинаковым сдвигом. Правило: выбирайте наименьшую длину с IC выше 0.06. Это самая частая точка, где новички ошибаются и уходят в неверном направлении. Я на одном из CTF убил полчаса, пытаясь подобрать ключ длиной 12, когда реальная длина была 4.

Восстанавливаем ключ: инструменты и ручной подход

Зная длину ключа, для каждой группы символов ищете сдвиг, при котором частотное распределение группы максимально совпадает со стандартным распределением английского языка. Типичная метрика — chi-squared.

На практике для решения crypto CTF задач проще использовать онлайн-инструменты:

dcode.fr — вставляете шифротекст, выбираете «Vigenere Cipher». Сервис автоматически определяет длину ключа (методами IC и Касиски) и подбирает ключ. Для подавляющего большинства CTF-задач на взлом шифра Виженера этого достаточно — расшифровка классического шифра онлайн без установки софта. Я бы сказал, что 80% задач на Виженер dcode.fr решает за вас.

Когда dcode.fr не справляется, причина обычно одна из двух: текст слишком короткий (менее 100 символов) или алфавит нестандартный. Тогда:

  • quipqiup.com — если после неудачной попытки Виженера вы подозреваете моноалфавитную подстановку, quipqiup решает такие задачи через комбинаторный подход (как указано в workflow HackTricks)
  • CyberChef — операция «Vigenere Decode» с ручным вводом ключа. Полезна, когда длину ключа вы уже определили через IC, а конкретные буквы подбираете перебором
  • Ручной перебор: для каждой позиции ключа пробуете 26 сдвигов, считаете chi-squared относительно эталонных частот, выбираете минимум

По данным CTF writeup для picoCTF (разбор на Medium), задача на Виженер среднего уровня решалась именно по этой цепочке: определение длины через IC, восстановление ключа через частотный анализ каждой позиции, дешифровка, флаг.

Криптоанализ CTF задач: инструменты и workflow

Набор инструментов для классической криптографии

Инструмент Назначение Тип
CyberChef Снятие кодировок, ROT, XOR, визуальный анализ Веб
dcode.fr Автоподбор классических шифров (Виженер, Цезарь, подстановки) Веб
quipqiup.com Решение моноалфавитных подстановок через паттерны слов Веб
Boxentriq Криптограммы, подстановочные шифры, Enigma Веб
xortool Определение длины XOR-ключа и его подбор CLI, Python
Ciphey Автоматическая дешифровка через ML-эвристики CLI, Python

Для большинства задач на классические шифры CTF хватает связки CyberChef + dcode.fr. Остальные подключаются, когда автоматика не справляется или задача нестандартная. Хотите тренировать именно криптоанализ — CryptoHack (cryptohack.org) и Cryptopals (cryptopals.com) дают задачи с возрастающей сложностью, от классических шифров до атак на современные протоколы.

Алгоритм решения crypto-задачи

Последовательность, которая покрывает большинство задач категории Crypto на соревнованиях начального и среднего уровня:

  1. Снимите кодировки. CyberChef, операция «Magic». Не помогло — вручную пробуете base64, base32, hex, URL-decoding. Каждый раз проверяете промежуточный результат
  2. Определите формат данных. Только буквы — классический шифр. Бинарные данные — XOR или современный алгоритм
  3. Для буквенного текста проверьте частоты. Неравномерные (одна буква заметно чаще) — моноалфавитная подстановка, несите в dcode.fr или quipqiup. Относительно ровные — Виженер
  4. Для ROT/Цезаря: CyberChef ROT Brute Force. 30 секунд
  5. Для XOR: однобайтовый брутфорс (скрипт выше). Не помогло — xortool для многобайтового ключа
  6. Для Виженера: dcode.fr автоматический. Не сработало — IC вручную через Python, подбор ключа побуквенно

Если ни один подход не дал результата — пересмотрите гипотезу. Возможно, перед вами не классический шифр, а современный алгоритм с уязвимой реализацией. Или комбинация нескольких преобразований: XOR + base64 + ROT. Снимайте слои по одному.

Совет из практики: читайте описание задачи дословно. Авторы CTF почти всегда оставляют подсказку — в названии задачи (например, «Caesar's Legacy» или «Poly is enough»), в имени приложенного файла, в комментариях метаданных. Пропустить подсказку и потратить час на неправильную гипотезу — стандартный тупик, через который проходят все, но через который нужно пройти только один раз.

Crypto — категория, которую новички в CTF стабильно обходят стороной. Все рвутся в web и pwn, потому что там «настоящий хакинг», а шифры кажутся скучной математикой. Но именно на классических шифрах формируется навык, который определяет скорость роста во всех остальных категориях: умение строить гипотезу, проверять её данными и отбрасывать без сожаления, когда данные не подтверждают.

Когда вы ломаете Виженер, вы не просто считаете индекс совпадений. Вы проходите полный цикл: «похоже на подстановку» — проверяете частоты — «распределение слишком ровное, значит полиалфавитная» — пробуете IC — получаете длину ключа — атакуете позиционно. Этот цикл — та же логика, что применяется при анализе обфусцированного трафика или реверсе бинарника с XOR-шифрованными строками. Техника T1027 из MITRE ATT&CK — обфускация файлов через XOR с коротким ключом — встречается в реальных семплах не реже, чем в CTF-задачах.

За полтора года участия в соревнованиях я наблюдаю одну и ту же закономерность: те, кто начинал с crypto и научился думать гипотезами, быстрее растут в остальных категориях. А те, кто перескочил сразу на бинарную эксплуатацию, чаще застревают там, где нет готового тулкита. Crypto учит думать, а не нажимать кнопки. Если только начинаешь копать в сторону ИБ — на курсе IB Basics эту базу можно пройти системно, с задачами и без занудства.

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

Поделиться

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

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

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