Skip to content
Урок 5. Счётчик кадров: replay против ребута

Урок 5. Счётчик кадров: replay против ребута

Урок 5. Счётчик кадров: replay-атака против ребута лисы

Паспорт урока

ПараметрЗначение
Место в модулеFoxHunter, модуль 2 «Безопасность протокола», урок 5 из 6
Длительность45 мин
Возраст13–16
ОборудованиеЛиса, охотник, фальшлиса с заряженным CAPTURED_PACKET
Предварительные знанияУрок 4: подпись, модель угроз
ПредметИнформатика, информационная безопасность
Подготовка педагога обязательна и занимает время. Для атаки 2 нужно заранее поймать реальный пакет: запустить настоящую лису и охотника, взять из монитора строку [RAW] и вписать 9 байт в CAPTURED_PACKET в скетче фальшлисы. Без этого урок не состоится. Сделать накануне, не на занятии.

Образовательные цели

ЦельБлумМиллерЧем доказывается
5.1Объяснять, почему подпись не защищает от повторапониматьзнает какОтвет: подпись верна, а пакет чужой
5.2Различать «честный ребут» и «replay-атаку» по динамике счётчикаанализироватьзнает какРазбор: застывший против растущего
5.3Обосновывать требование нескольких пакетов для ресинхронизацииоцениватьзнает какОтвет про RESYNC_N
5.4Проектировать правило принятия решения при неоднозначных данныхсоздаватьпоказывает какСобственный алгоритм различения

Сценарий занятия (45 минут)

ВремяБлокЧто делает педагогЧто делают ученики
0–5RetrievalМини-квиз по уроку 4Пишут, разбор
5–10Вызов«Подпись есть. Можно ли всё же обмануть?»Выдвигают гипотезы
10–18Атака 2Запускает replay: подпись верна, но отвергнутНаблюдают, объясняют
18–28КульминацияПерезагружает настоящую лису — её принялиФормулируют различие
28–38ТеорияМонотонный счётчик, ресинхронизацияРазбирают алгоритм
38–45Практика и ДЗЗадачиРешают

Блок 1. Вызов (5–10 мин)

Постановка

«На прошлом уроке мы защитились подписью: подделать пакет без ключа нельзя. Вопрос: можно ли обмануть охотника, не подделывая ничего?»

Дать классу 3 минуты на гипотезы. Если никто не догадался, подсказка:

«А обязательно ли злоумышленнику создавать пакет? Что ещё можно сделать с пакетом, который уже летал в эфире?»

Ожидаемый ответ: записать и послать снова.

Ключевая мысль

Подпись подтверждает: «этот пакет когда-то создал владелец ключа». Она ничего не говорит о том, когда. Записанный пакет остаётся математически безупречным вечно.


Блок 2. Атака 2: повтор (10–18 мин)

Демонстрация

Педагог запускает фальшлису в режиме атаки 2. Она шлёт заранее пойманный настоящий пакет — байт в байт, без изменений.

Что увидят дети

[SEC] REJECT ... SIG:OK FCNT:REPLAY

Обратить внимание класса на важное: SIG:OK. Подпись прошла проверку! Пакет подлинный — и всё равно отвергнут.

Разговор

«Подпись верна. Охотник признаёт: этот пакет действительно создала настоящая лиса. И всё-таки не принимает. Почему?»

ГипотезаРеакция
«Он видит, что пакет повторяется»Верно. Но по какому признаку?
«Данные одинаковые»А если бы менялось напряжение батареи? Нужен более надёжный признак
«Счётчик не растёт»Точный ответ. Записать на доску

Что показать в мониторе

Вывести рядом два потока:

Настоящая лисаФальшлиса (replay)
fcnt = 1050fcnt = 127
fcnt = 1051fcnt = 127
fcnt = 1052fcnt = 127
растётзастыл

Блок 3. Кульминация урока (18–28 мин)

Это методически сильнейший момент всего модуля. Провести его аккуратно, не торопясь.

Постановка ловушки

«Итак, правило простое: счётчик должен расти. Если пришёл пакет со счётчиком меньше запомненного — это атака, отвергаем. Согласны?»

Класс обычно соглашается.

«Хорошо. А теперь я просто выключу и включу настоящую лису.»

Что произойдёт

После перезагрузки fcnt настоящей лисы обнуляется и начинается с малых значений: 1, 2, 3… Охотник помнит 1052.

По только что принятому правилу настоящую лису надо отвергнуть. Но она честная!

Постановка проблемы

На доску две ситуации:

Replay-атакаРебут настоящей лисы
Подписьвернаверна
fcnt меньше запомненногодада
Кто это на самом делезлоумышленникчестная лиса

«Данные выглядят одинаково. Как отличить?»

Разгадка

Дать классу подумать 3–4 минуты. Направляющий вопрос:

«Посмотрите не на одно значение, а на несколько подряд. Что делает счётчик в каждом случае?»

Replay-атакаРебут
127, 127, 127, 127…1, 2, 3, 4…
застылрастёт

Формулировка, которую надо получить от детей:

Различает не значение счётчика, а его динамика. Атака переигрывает один и тот же пакет — счётчик стоит. Перезагруженная лиса продолжает работать — счётчик растёт, просто с нуля.

Один и тот же механизм — монотонный счётчик — отвечает на два разных вопроса, если смотреть на него во времени, а не в моменте.


Блок 4. Теория (28–38 мин)

4.1. Базовый уровень (13–14 лет)

Через нумерацию писем.

Друг присылает тебе письма и нумерует их: №1, №2, №3. Ты помнишь последний номер. Приходит письмо №2 — ты уже такое получал, значит кто-то подсунул копию старого.

Но однажды друг переехал и начал нумерацию заново: №1, №2, №3. Первое такое письмо выглядит как копия. А потом ты видишь: номера растут. Копия так себя не ведёт — она всегда одна и та же.

4.2. Углублённый уровень (14–16 лет)

Шаг 1. Монотонный счётчик кадров.

fcnt — 4-байтовое число, увеличивающееся на единицу с каждым отправленным пакетом. Приёмник хранит последнее принятое значение и применяет правило:

принять, если fcntновый>fcntсохранённый\text{принять, если } fcnt_{\text{новый}} > fcnt_{\text{сохранённый}}

Это защита от повтора: записанный пакет несёт старое значение, и правило его отсекает.

Шаг 2. Проблема перезагрузки.

Счётчик хранится в оперативной памяти. При сбросе питания он обнуляется. Возможные решения:

РешениеПлюсМинус
Хранить fcnt в энергонезависимой памятипереживает ребутизнос памяти при частой записи
Разрешить сброс на серверепростооткрывает дыру для replay
Распознавать ребут по динамикене требует памятисложнее логика, есть окно уязвимости

В нашем стенде выбран третий путь — он же самый поучительный.

Шаг 3. Алгоритм ресинхронизации.

принят пакет, подпись OK
если fcnt > сохранённого:
    принять, обновить сохранённый
иначе:
    # подозрительно: replay или ребут?
    если это первый такой пакет:
        запомнить кандидата, счётчик_подряд = 1
    иначе если fcnt == предыдущий_кандидат + 1:
        счётчик_подряд += 1
        если счётчик_подряд >= RESYNC_N:
            [RESYNC] — это ребут, принять лису обратно
    иначе:
        [SEC] REJECT ... FCNT:REPLAY

Шаг 4. Зачем требовать несколько пакетов подряд.

Одного растущего пакета мало. Злоумышленник, записавший два последовательных пакета лисы, может проигрывать их по очереди — счётчик будет «расти» на единицу. Требование RESYNC_N подряд растущих значений поднимает планку: атакующему нужно записать целую серию.

Это не абсолютная защита, а повышение стоимости атаки — типичный и честный приём в безопасности.

Честная оговорка для сильных учеников. Логика ресинхронизации по определению создаёт окно уязвимости: если злоумышленник запишет RESYNC_N последовательных пакетов, он сможет заставить приёмник принять свою серию.

Промышленное решение — хранение счётчика в энергонезависимой памяти плюс проверка на стороне сервера. В LoRaWAN сброс счётчика разрешают только для отладочных ABP-устройств и явно считают это ослаблением защиты.

Признание ограничений собственного решения — обязательная часть инженерной работы.

Шаг 5. Где встречается тот же механизм.

СистемаКак называетсяНазначение
LoRaWANFCntUp / FCntDownзащита кадров от повтора
TLS (HTTPS)sequence numberзащита записей от повтора
IPsecanti-replay windowскользящее окно принятых номеров
Платёжные системыномер транзакциизащита от повторного списания
Автомобильные брелокиrolling codeзащита от записи и повтора сигнала
Пример, понятный всем. Автомобильный брелок использует ровно этот механизм: каждое нажатие отправляет новый код из последовательности, известной обеим сторонам. Записанный злоумышленником сигнал уже «использован» и машиной не принимается. Ранние системы без rolling code вскрывались именно записью и повтором.

Блок 5. Практические задачи (38–45 мин)

Уровень A (13–14 лет)

A1. Охотник напечатал SIG:OK FCNT:REPLAY. Что это значит?

Ответ

Подпись верна — пакет действительно был когда-то создан настоящей лисой. Но счётчик кадров не вырос, значит это запись старого пакета, воспроизведённая заново. Охотник отвергает.

A2. Почему подпись не спасает от повтора?

Ответ

Подпись подтверждает авторство и целостность, но не содержит информации о времени. Записанный пакет остаётся подлинным — злоумышленнику не нужно ничего подделывать, он просто повторяет чужое.

A3. Лиса перезагрузилась, её счётчик пошёл с единицы. Почему охотник не считает её атакой?

Ответ

Охотник смотрит не на одно значение, а на несколько подряд. У перезагруженной лисы счётчик растёт (1, 2, 3), у повтора — стоит на месте. Увидев несколько растущих значений, охотник понимает, что это честный перезапуск, и ресинхронизируется.

Уровень B (14–15 лет)

B1. Охотник помнит fcnt = 500. Приходят пакеты со значениями 3, 4, 5, 6 (подпись верна во всех). Как поступит охотник при RESYNC_N = 3?

Решение
  • fcnt = 3: меньше сохранённого 500 → подозрение, запоминается кандидат, счётчик подряд = 1;
  • fcnt = 4: равен кандидат + 1 → счётчик подряд = 2;
  • fcnt = 5: → счётчик подряд = 3, достигнут RESYNC_N[RESYNC], лиса принята, сохранённое значение обновляется на 5;
  • fcnt = 6: больше сохранённого 5 → принимается обычным образом.

Вывод: охотник опознал перезагрузку за три пакета, то есть менее чем за секунду при BEACON_MS = 300.

B2. Почему нельзя принять правило «принимать любой fcnt, если подпись верна»?

Ответ

Тогда replay-атака проходит полностью: записанный пакет имеет верную подпись и будет принят сколько угодно раз. Злоумышленник сможет имитировать присутствие лисы там, где её нет, — то есть увести детей в ложном направлении.

Подпись и счётчик закрывают разные угрозы, и нужны оба.

B3. Злоумышленник записал два последовательных пакета (fcnt = 100 и 101) и проигрывает их по очереди. Пройдёт ли он проверку при RESYNC_N = 3?

Решение

Последовательность его передач: 100, 101, 100, 101, 100…

  • 100 → кандидат, подряд = 1
  • 101 → равно 100 + 1, подряд = 2
  • 100 → не равно 101 + 1, цепочка рвётся, счётчик сбрасывается

Порог RESYNC_N = 3 не достигается никогда. Атака не проходит.

Но если бы он записал три пакета (100, 101, 102), цепочка достигла бы трёх и ресинхронизация сработала бы. Это и есть окно уязвимости, о котором сказано выше.

Уровень C (15–16 лет)

C1. Предложите улучшение схемы ресинхронизации, повышающее стойкость без энергонезависимой памяти. Оцените, что теряется.

Разбор

Возможные направления:

  1. Увеличить RESYNC_N (до 10–20). Атакующему нужна длинная запись. Теряем: время восстановления после честного ребута растёт.
  2. Требовать роста в течение временного окна. Проверять не только последовательность, но и интервал прихода (300 мс). Записанная серия, проигрываемая с другим темпом, не пройдёт. Теряем: усложнение, чувствительность к потерям пакетов.
  3. Добавить метку времени в пакет. Приёмник отвергает пакеты старше N секунд. Теряем: нужны синхронные часы у лисы и охотника.
  4. Челлендж-ответ. Охотник посылает случайное число, лиса его подписывает. Полностью закрывает replay. Теряем: маяк перестаёт быть односторонним, лисе нужен приёмник, растут энергопотребление и сложность.

Правильный вывод: вариант 4 — самый стойкий и самый дорогой. Односторонний маяк принципиально уязвимее двустороннего протокола. Выбор определяется ценой атаки и стоимостью защиты, а не стремлением к абсолютной защите.

C2. Счётчик fcnt — 4-байтовый. Через сколько времени он переполнится при BEACON_MS = 300? Что произойдёт при переполнении?

Решение

Максимум 4-байтового беззнакового числа: 2³² − 1 ≈ 4,295 · 10⁹.

При 300 мс на пакет: 1 / 0,3 ≈ 3,33 пакета в секунду.

t=4,2951093,331,29109 с41 годt = \frac{4{,}295 \cdot 10^9}{3{,}33} \approx 1{,}29 \cdot 10^9\ \text{с} \approx \mathbf{41\ \text{год}}

При переполнении счётчик обнулится, и приёмник воспримет это как ребут — сработает механизм ресинхронизации, лиса будет принята. То есть переполнение обрабатывается корректно, хоть и не специально.

Замечание: 41 год делает проблему практически неактуальной. Но в системах с частой передачей (например, каждые 10 мс) счётчик переполнился бы за год, и это уже требует обработки. Правильный инженерный рефлекс — посчитать срок переполнения, а не полагаться на «наверное, хватит».

C3. Сравните защиту от replay в нашем стенде и в LoRaWAN. Что промышленный протокол делает иначе?

Разбор
АспектНаш стендLoRaWAN
Счётчикfcnt, 4 байта, в RAMFCntUp, сессионный
Хранениетеряется при сбросе питанияна сервере; на устройстве — в EEPROM (в проде)
Проверкана приёмнике (охотник)на сетевом сервере
Ресинхронизацияпо динамике, RESYNC_N подрядтолько явным разрешением «disable frame-counter validation»
Подпись1 байт XOR4 байта AES-CMAC
Направлениеодносторонний маякдвусторонний, есть даунлинк

Ключевое отличие: LoRaWAN не пытается «умно распознать» ребут — он считает сброс счётчика ослаблением защиты и требует явного разрешения администратора. Наш стенд идёт на компромисс ради простоты, и это честно задокументировано.

Урок: промышленные протоколы часто отказываются от изящных эвристик в пользу строгих правил, потому что эвристика — это всегда окно для атаки.


Ответы на вопросы, которые прозвучат

Вопрос ученикаКак отвечать
«Почему просто не сохранять счётчик в память?»Так и делают в реальных системах. Но флеш-память имеет ограниченный ресурс записи (десятки тысяч циклов), а лиса шлёт три пакета в секунду — память износится очень быстро. Нужны хитрые схемы записи (см. ДЗ уровня C)
«А если злодей запишет много пакетов?»Тогда он сможет пройти ресинхронизацию — и это честное ограничение нашей схемы. В проде счётчик хранят надёжно, а сброс запрещают
«Можно ли добавить время в пакет?»Да, хорошее решение. Но требует синхронных часов у лисы и охотника — в нашем стенде их нет
«Что если лиса потеряет пакеты — счётчик перескочит?»Ничего страшного: правило требует роста, а не «ровно на единицу». Пропуски нормальны и как раз показывают потери в эфире
«Брелок от машины так же работает?»Да, это тот же механизм — rolling code. Ранние брелоки без него вскрывались записью и повтором
«А если злодей ретранслирует сигнал вживую?»Отличный вопрос — счётчик при этом растёт честно, и защита не срабатывает. Это relay-атака, от неё защищаются измерением времени распространения сигнала. У нас такой защиты нет

Раздаточный лист (для печати)

Урок 5. Счётчик кадров

Задача урока: одинаковые на вид данные — разные причины. Как различить?

Replay-атакаРебут настоящей лисы
Подпись
fcnt меньше запомненного
Динамика fcnt
Решение охотника

Правило приёмника:

принять, если fcnt > сохранённого
иначе: смотреть, РАСТЁТ ли он в следующих пакетах
       RESYNC_N подряд растущих -> ребут, принять
       застыл -> атака, отвергнуть

Задание. Охотник помнит fcnt = 500, RESYNC_N = 3. Заполните:

ПришлоБольше 500?Растёт подряд?Решение охотника
3
4
5
6

Где ещё применяется тот же механизм:

  1. ________________________
  2. ________________________
  3. ________________________

Главный вывод урока своими словами:

______________________________________________________

______________________________________________________


Домашнее задание

Обязательная часть

Врайтап по рубрике А. Обязательный пункт: опишите момент, когда правило «счётчик должен расти» оказалось недостаточным, и как его починили.

Уровень A

Найти три системы, где что-то нумеруется по порядку для защиты от повтора (чеки, билеты, номера транзакций, талоны). Описать, что произойдёт при повторении номера.

Уровень B

Придумать и описать сценарий атаки на охотника, который не закрывается ни подписью, ни счётчиком. Объяснить, почему существующие механизмы не помогают.

Ориентир для педагога

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

Уровень C

Маяк имеет энергонезависимую память с ресурсом 100 000 циклов записи. Нужно хранить счётчик так, чтобы памяти хватило на 10 лет при 3,33 пакета в секунду. Предложите схему записи и обоснуйте расчётом.

Ориентир для педагога

Расчёт объёма задачи:

Пакетов за 10 лет: 3,33 · 10 · 365 · 24 · 3600 ≈ 1,05 · 10⁹.

Если писать каждый пакет — 10⁹ записей при ресурсе 10⁵. Не хватает в 10 000 раз.

Требуется: не менее 10 501 пакета на одну запись.

Шаг записи NЗаписей за 10 летХватает?
1 0001 050 149нет
10 000105 015нет (на грани)
100 00010 501да, с запасом ×10

Схема решения: записывать счётчик не каждый пакет, а раз в N = 100 000. При старте после сброса питания прочитать сохранённое значение и сразу прибавить N — тогда новый счётчик заведомо больше любого, который был реально использован. Цена: после каждого ребута «теряется» до 100 000 номеров, но их запас (2³²) это позволяет — хватит на 43 000 перезагрузок.

Дополнительное улучшение (для самых сильных): wear leveling — писать не в одну ячейку, а по кругу в несколько, что умножает ресурс на их количество.

Это реальная инженерная задача: именно так решают проблему в промышленных LoRaWAN-узлах.


Итог урока: что записать в журнал

Вывод урока 5

  1. Подпись подтверждает авторство, но не время. Записанный пакет остаётся подлинным.
  2. Защита от повтора — монотонный счётчик кадров: приёмник принимает только растущие значения.
  3. Ребут честной лисы выглядит как атака: счётчик тоже становится малым.
  4. Различает динамика: у атаки счётчик застыл, у ребута — растёт. Смотреть надо на серию, а не на одно значение.
  5. Требование RESYNC_N подряд растущих значений повышает стоимость атаки, но не делает её невозможной — это честный компромисс.
  6. Тот же механизм работает в LoRaWAN, TLS, IPsec, платёжных системах и автомобильных брелоках.

Связь с курсом

Что родилось на этом урокеГде станет инструментом
Защита от replayPowerSentry урок 7 (FCnt в LoRaWAN)
«Смотреть на динамику, а не на значение»RFCurtain (тренд против порога), BeaconRadio (свежесть фикса)
Различение похожих ситуаций по контекстуBeaconRadio урок 5 (спуфинг: HDOP хороший, но ГЛОНАСС ноль)
Повышение стоимости атаки вместо абсолютной защитыЗащита выпускного проекта

Чек-лист педагога перед уроком

  • Накануне: пойман реальный пакет, байты вписаны в CAPTURED_PACKET
  • Проверено: атака 2 даёт SIG:OK FCNT:REPLAY
  • Проверено: перезагрузка настоящей лисы даёт [RESYNC] и приём
  • Монитор порта настроен показывать fcnt каждого пакета
  • Раздаточный лист распечатан
  • Продуман момент кульминации: не выдать разгадку раньше времени